import 'dart:async';
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'simple_e2ee_service.dart';
import 'local_key_backup_service.dart';
import 'local_message_store.dart';
import 'auth_service.dart';

/// Manages automatic encrypted cloud backups of chat data.
///
/// Flow: User enables backup → sets password once → chats auto-backup.
/// To restore on another device, user enters the same password.
class ChatBackupManager {
  static final ChatBackupManager _instance = ChatBackupManager._internal();
  static ChatBackupManager get instance => _instance;

  ChatBackupManager._internal();

  static const String _passwordKey = 'chat_backup_password_v1';
  static const String _enabledKey = 'chat_backup_enabled';
  static const String _lastBackupKey = 'chat_backup_last_at';
  static const String _lastBackupCountKey = 'chat_backup_last_msg_count';
  static const Duration _minBackupInterval = Duration(minutes: 10);
  static const int _minNewMessages = 1;

  final FlutterSecureStorage _secureStorage = const FlutterSecureStorage();
  final SimpleE2EEService _e2ee = SimpleE2EEService();

  Timer? _debounceTimer;
  bool _backupInProgress = false;
  DateTime? _lastBackupAt;
  int _lastBackupMessageCount = 0;
  bool? _enabledCache;

  /// Whether backup has been set up (password stored + enabled)
  Future<bool> get isEnabled async {
    if (_enabledCache != null) return _enabledCache!;
    final prefs = await SharedPreferences.getInstance();
    _enabledCache = prefs.getBool(_enabledKey) ?? false;
    return _enabledCache!;
  }

  /// Whether a backup password has been configured
  Future<bool> get hasPassword async {
    final pw = await _secureStorage.read(key: _passwordKey);
    return pw != null && pw.isNotEmpty;
  }

  /// Last backup timestamp
  Future<DateTime?> get lastBackupAt async {
    if (_lastBackupAt != null) return _lastBackupAt;
    final prefs = await SharedPreferences.getInstance();
    final ms = prefs.getInt(_lastBackupKey);
    if (ms != null) {
      _lastBackupAt = DateTime.fromMillisecondsSinceEpoch(ms);
    }
    return _lastBackupAt;
  }

  /// Number of messages in last backup
  Future<int> get lastBackupMessageCount async {
    if (_lastBackupMessageCount > 0) return _lastBackupMessageCount;
    final prefs = await SharedPreferences.getInstance();
    _lastBackupMessageCount = prefs.getInt(_lastBackupCountKey) ?? 0;
    return _lastBackupMessageCount;
  }

  /// Set up backup: store password and enable auto-backup.
  /// Called once during the setup flow.
  Future<void> enable(String password) async {
    await _secureStorage.write(key: _passwordKey, value: password);
    final prefs = await SharedPreferences.getInstance();
    await prefs.setBool(_enabledKey, true);
    _enabledCache = true;

    // Perform initial backup immediately
    await _performBackup();
  }

  /// Disable auto-backup and clear stored password.
  Future<void> disable() async {
    await _secureStorage.delete(key: _passwordKey);
    final prefs = await SharedPreferences.getInstance();
    await prefs.setBool(_enabledKey, false);
    _enabledCache = false;
    _debounceTimer?.cancel();
  }

  /// Change the backup password. Re-encrypts and uploads immediately.
  Future<void> changePassword(String newPassword) async {
    await _secureStorage.write(key: _passwordKey, value: newPassword);
    await _performBackup();
  }

  /// Schedule a backup after a debounce period.
  /// Call this after sending/receiving messages.
  void scheduleBackup() {
    _debounceTimer?.cancel();
    _debounceTimer = Timer(const Duration(seconds: 30), () {
      _tryAutoBackup();
    });
  }

  /// Trigger an immediate backup if conditions are met.
  /// Called by SyncManager after sync, or on app background.
  Future<void> triggerBackupIfNeeded() async {
    await _tryAutoBackup();
  }

  /// Force an immediate backup regardless of schedule.
  Future<void> forceBackup() async {
    await _performBackup();
  }

  /// Restore from cloud backup using the given password.
  /// Returns restore result with counts.
  Future<Map<String, dynamic>> restoreFromCloud(String password) async {
    return await LocalKeyBackupService.restoreFromCloud(
      password: password,
      e2eeService: _e2ee,
    );
  }

  /// Get current local message count for status display.
  Future<int> getLocalMessageCount() async {
    final records = await LocalMessageStore.instance.getAllMessageRecords();
    return records.length;
  }

  /// Clear all local message data.
  Future<void> clearLocalMessages() async {
    await LocalMessageStore.instance.clearAll();
  }

  /// Reset everything on sign-out.
  void reset() {
    _debounceTimer?.cancel();
    _lastBackupAt = null;
    _lastBackupMessageCount = 0;
    _enabledCache = null;
    _backupInProgress = false;
  }

  // --- Private ---

  Future<void> _tryAutoBackup() async {
    if (_backupInProgress) return;
    if (!AuthService.instance.isAuthenticated) return;

    final enabled = await isEnabled;
    if (!enabled) return;

    final hasPw = await hasPassword;
    if (!hasPw) return;

    // Check minimum interval
    final last = await lastBackupAt;
    if (last != null && DateTime.now().difference(last) < _minBackupInterval) {
      return;
    }

    // Check if there are new messages since last backup
    final currentCount = await getLocalMessageCount();
    final lastCount = await lastBackupMessageCount;
    if (currentCount <= 0) return;
    if (currentCount - lastCount < _minNewMessages && last != null) return;

    await _performBackup();
  }

  Future<void> _performBackup() async {
    if (_backupInProgress) return;
    _backupInProgress = true;

    try {
      final password = await _secureStorage.read(key: _passwordKey);
      if (password == null || password.isEmpty) return;

      if (!_e2ee.isReady) {
        await _e2ee.initialize();
        if (!_e2ee.isReady) return;
      }

      final backup = await LocalKeyBackupService.createEncryptedBackup(
        password: password,
        e2eeService: _e2ee,
        includeMessages: true,
        includeKeys: true,
      );

      await LocalKeyBackupService.uploadToCloud(backup: backup);

      // Record success
      final now = DateTime.now();
      _lastBackupAt = now;
      final msgCount = await getLocalMessageCount();
      _lastBackupMessageCount = msgCount;

      final prefs = await SharedPreferences.getInstance();
      await prefs.setInt(_lastBackupKey, now.millisecondsSinceEpoch);
      await prefs.setInt(_lastBackupCountKey, msgCount);

      debugPrint('[ChatBackup] Auto-backup complete: $msgCount messages');
    } catch (e) {
      debugPrint('[ChatBackup] Auto-backup failed: $e');
    } finally {
      _backupInProgress = false;
    }
  }
}
