import 'dart:convert';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:uuid/uuid.dart';

class RemoteStateStore {
  static const _storage = FlutterSecureStorage(
    aOptions: AndroidOptions(
      encryptedSharedPreferences: true,
      resetOnError: true,
    ),
  );

  static const _kWsSessionId = 'ws_session_id';
  static const _kDeviceId = 'device_id';
  static const _kProcessedRing = 'ws_processed_events_ring';
  static const _kLastSyncIso = 'remote_last_sync_iso';

  // ✅ NEW: last seen timestamp (ms) come sync.js: ws_last_seen
  static const _kWsLastSeenMs = 'ws_last_seen_ms';

  // ---------------------------
  // WS session id
  // ---------------------------

  Future<String> getOrCreateSessionId() async {
    var id = await _storage.read(key: _kWsSessionId);
    if (id == null || id.isEmpty) {
      id = const Uuid().v4();
      await _storage.write(key: _kWsSessionId, value: id);
    }
    return id;
  }

  Future<void> clearSessionId() => _storage.delete(key: _kWsSessionId);

  /// ✅ Alias “sync.js-like”: reset session id (usato quando sessione dormiente > 2 min)
  Future<void> resetSessionId() => clearSessionId();

  // ---------------------------
  // Last sync ISO
  // ---------------------------

  Future<String?> getLastSyncIso() => _storage.read(key: _kLastSyncIso);

  Future<void> setLastSyncIso(String iso) =>
      _storage.write(key: _kLastSyncIso, value: iso);

  // ---------------------------
  // WS last seen (ms)
  // ---------------------------

  /// Ritorna l’ultimo timestamp (ms) in cui abbiamo ricevuto un messaggio WS.
  Future<int> getWsLastSeenMs() async {
    final raw = await _storage.read(key: _kWsLastSeenMs);
    if (raw == null || raw.isEmpty) return 0;
    final v = int.tryParse(raw);
    return v ?? 0;
  }

  /// Salva l’ultimo timestamp (ms) in cui abbiamo ricevuto un messaggio WS.
  Future<void> setWsLastSeenMs(int ms) async {
    await _storage.write(key: _kWsLastSeenMs, value: ms.toString());
  }

  Future<void> clearWsLastSeenMs() => _storage.delete(key: _kWsLastSeenMs);

  // ---------------------------
  // Processed events ring
  // ---------------------------

  Future<List<String>> loadProcessedRing({int maxSize = 2000}) async {
    final raw = await _storage.read(key: _kProcessedRing);
    if (raw == null || raw.isEmpty) return <String>[];
    try {
      final v = jsonDecode(raw);
      if (v is List) {
        final list = v.whereType<String>().toList();
        return list.length > maxSize ? list.sublist(list.length - maxSize) : list;
      }
    } catch (_) {}
    return <String>[];
  }

  Future<void> saveProcessedRing(List<String> ring, {int maxSize = 2000}) async {
    final trimmed = ring.length > maxSize ? ring.sublist(ring.length - maxSize) : ring;
    await _storage.write(key: _kProcessedRing, value: jsonEncode(trimmed));
  }

// ---------------------------
// Device ID (persistente)
// ---------------------------

Future<String> getOrCreateDeviceId() async {
  var id = await _storage.read(key: _kDeviceId);
  if (id == null || id.isEmpty) {
    id = const Uuid().v4();
    await _storage.write(key: _kDeviceId, value: id);
  }
  return id;
}

// Alias richiesti dal RemoteSyncEngine
Future<String> getSessionId() => getOrCreateSessionId();
Future<String> getDeviceId() => getOrCreateDeviceId();

}

class EventRingDeduper {
  EventRingDeduper(this.store, {this.maxSize = 2000});

  final RemoteStateStore store;
  final int maxSize;

  final List<String> _ring = [];
  final Set<String> _set = {};

  Future<void> init() async {
    final saved = await store.loadProcessedRing(maxSize: maxSize);
    _ring
      ..clear()
      ..addAll(saved);
    _set
      ..clear()
      ..addAll(saved);
  }

  bool has(String? id) => id != null && id.isNotEmpty && _set.contains(id);

  Future<void> mark(String? id) async {
    if (id == null || id.isEmpty) return;
    if (_set.contains(id)) return;

    _ring.add(id);
    _set.add(id);

    while (_ring.length > maxSize) {
      final old = _ring.removeAt(0);
      _set.remove(old);
    }

    await store.saveProcessedRing(_ring, maxSize: maxSize);
  }

}
