import 'package:flutter/material.dart';
import '/data/models/contact_model.dart';
import '/data/repositories/contact_repository.dart';
import '/domain/services/crypto_service.dart';
import 'dart:isolate';
import 'package:cryptography/cryptography.dart';
import 'package:flutter/foundation.dart';
import 'package:chepuhagram/data/models/message_model.dart';

class ContactProvider extends ChangeNotifier {
  final ContactRepository _repository = ContactRepository();
  final CryptoService _cryptoService;

  ContactProvider(this._cryptoService);
  final Map<int, SecretKey> _sharedKeysCache = {};
  List<Contact> _contacts = [];
  List<Contact> _allContacts = [];
  bool _isLoading = false;
  bool _isFirstLoad = true;
  String? _error;
  int? _currentUserId;

  List<Contact> get contacts => _contacts;
  List<Contact> get allContacts => _allContacts;
  bool get isLoading => _isLoading;
  String? get error => _error;
  Map<int, SecretKey> get sharedKeysCache => _sharedKeysCache;

  void setSharedKey(int contactId, SecretKey key) {
    _sharedKeysCache[contactId] = key;
  }

  void setCurrentUserId(int? id) {
    _currentUserId = id;
    notifyListeners();
  }

  int? getCurrentUserId() {
    return _currentUserId;
  }

  Future<void> loadContacts({bool enrichContacts = true}) async {
    if (_isFirstLoad) {
      _isFirstLoad = false;
      _isLoading = true;
    }
    _error = null;
    notifyListeners();

    try {
      final allContacts = await _repository.fetchChatContacts();
      final userIdCopy = _currentUserId;
      _contacts = await Isolate.run(() {
        return allContacts
            .where((contact) => contact.id != userIdCopy)
            .toList();
      });
      // Check if user changed during isolate execution
      if (userIdCopy != _currentUserId) {
        return; // Discard stale data
      }
      _allContacts = _contacts;
      _isLoading = false;
      notifyListeners();

      if (enrichContacts) {
        await _enrichContactsWithLastMessages();
      }
    } catch (e) {
      _error = e.toString();
      print("❌ ОШИБКА ПРИ ЗАГРУЗКЕ КОНТАКТОВ: $_error");
    } finally {
      if (_error != null) {
        _isLoading = false;
      }
      notifyListeners();
    }
  }

  Future<void> loadAllContactsForNewChat() async {
    _isLoading = true;
    _error = null;
    notifyListeners();

    try {
      final allContacts = await _repository.fetchAllUsers();
      _allContacts = allContacts
          .where((contact) => contact.id != _currentUserId)
          .toList();
    } catch (e) {
      _error = e.toString();
    } finally {
      _isLoading = false;
      notifyListeners();
    }
  }

  
  String _getMediaPreview(MessageType type) {
    switch (type) {
      case MessageType.videoNote:
        return '[Кружок]';
      case MessageType.voiceNote:
        return '[Голосовое]';
      case MessageType.image:
        return '[Фото]';
      case MessageType.video:
        return '[Видео]';
      case MessageType.file:
        return '[Файл]';
      case MessageType.text:
      default:
        return '';
    }
  }

  Future<void> _enrichContactsWithLastMessages() async {
    final myPrivKeyBase64 = await _cryptoService.getPrivateKey();
    if (myPrivKeyBase64 == null) return;

    // Создаем локальные копии для передачи
    final contactsToProcess = List<Contact>.from(_contacts);
    final cacheCopy = Map<int, SecretKey>.from(_sharedKeysCache);

    print('Avialable cache for contacts: ${cacheCopy.length}');

    try {
      final updatedContacts = await compute(CryptoService.bulkDecryptContacts, {
        'contacts': contactsToProcess,
        'privKey': myPrivKeyBase64,
        'cache': cacheCopy,
      });
      for (var contact in updatedContacts) {
        print(
          'Decrypted contact: ${contact.name} ${contact.surname}, lastMessage: ${contact.lastMessage}, isDecrypted: ${contact.isLastMsgDecrypted}',
        );
      }
      _contacts = updatedContacts;
      notifyListeners();
    } catch (e) {
      print("Ошибка дешифровки: $e");
    }
  }

  Future<void> updateContact(
    int userId, {
    String? lastMessage,
    DateTime? lastMessageTime,
    bool? isLastMsgDecrypted,
    int? unreadCount,
  }) async {
    try {
      final updatedContact = await _repository.fetchContactById(userId);
      final index = _contacts.indexWhere((c) => c.id == userId);
      if (index != -1) {
        final existing = _contacts[index];
        _contacts[index] = existing.copyWith(
          username: updatedContact.username,
          name: updatedContact.name,
          surname: updatedContact.surname,
          avatarUrl: updatedContact.avatarUrl,
          avatarFileId: updatedContact.avatarFileId,
          isOnline: updatedContact.isOnline,
          publicKey: updatedContact.publicKey,
          lastMessage: lastMessage ?? existing.lastMessage,
          lastMessageTime: lastMessageTime ?? existing.lastMessageTime,
          isLastMsgDecrypted: isLastMsgDecrypted ?? existing.isLastMsgDecrypted,
          unreadCount: unreadCount ?? existing.unreadCount,
          lastMessageId: updatedContact.lastMessageId,
        );
        print(
          "Контакт ${updatedContact.name} ${updatedContact.surname} ${updatedContact.id} ${updatedContact.avatarFileId} ${updatedContact.avatarUrl} обновлен",
        );
        notifyListeners();
      }
    } catch (e) {
      print("Error updating contact: $e");
    }
  }

  Future<void> updateContactOnlineStatus(int userId, bool isOnline) async {
    try {
      final index = _contacts.indexWhere((c) => c.id == userId);
      if (index != -1) {
        final existing = _contacts[index];
        _contacts[index] = existing.copyWith(
          isOnline: isOnline,
          username: existing.username,
          name: existing.name,
          surname: existing.surname,
          avatarUrl: existing.avatarUrl,
          avatarFileId: existing.avatarFileId,
          publicKey: existing.publicKey,
        );
        print("Контакт ${existing.name} ${existing.surname} онлайн обновлен");
        notifyListeners();
      }
    } catch (e) {
      print("Error updating contact: $e");
    }
  }

  Future<void> updateContactLastMessage(int contactId, {String? lastMessage, DateTime? lastMessageTime, bool? isLastMsgDecrypted, int? lastMessageId, bool isEdited = false}) async {
    try {
      final index = _contacts.indexWhere((c) => c.id == contactId);
      if (index != -1) {
        final existing = _contacts[index];
        String displayMessage;
        if (isEdited) {
          final baseMessage = lastMessage ?? existing.lastMessage;
          final rawMessage = baseMessage != null && baseMessage.isNotEmpty
              ? baseMessage
              : 'Сообщение изменено';
          displayMessage = rawMessage.endsWith('(изменено)')
              ? rawMessage
              : '$rawMessage (изменено)';
        } else {
          displayMessage = lastMessage ?? existing.lastMessage ?? '';
        }

        _contacts[index] = existing.copyWith(
          lastMessage: displayMessage.isNotEmpty ? displayMessage : null,
          lastMessageTime: lastMessageTime,
          isLastMsgDecrypted: isLastMsgDecrypted ?? existing.isLastMsgDecrypted,
          lastMessageId: lastMessageId,
        );
        print("Последнее сообщение контакта ${existing.name} обновлено: $displayMessage");
        notifyListeners();
      }
    } catch (e) {
      print("Error updating contact last message: $e");
    }
  }

  Future<void> refreshContactLastMessage(int contactId) async {
    try {
      // Получить предпоследнее сообщение из базы данных
      final lastMessages = await _repository.getLastMessagesForContact(contactId, limit: 2);
      if (lastMessages.isNotEmpty) {
        final lastMsg = lastMessages.first;
        final contact = _contacts.firstWhere((c) => c.id == contactId);
        final messageId = int.tryParse(lastMsg['id'].toString());
        final timestamp = DateTime.tryParse(lastMsg['timestamp']?.toString() ?? '');
        final myPrivKeyBase64 = await _cryptoService.getPrivateKey();
        if (myPrivKeyBase64 != null && contact.publicKey != null) {
          try {
            final sharedSecret = await _cryptoService.deriveSharedSecret(
              myPrivKeyBase64,
              contact.publicKey!,
            );
            final decryptedText = await _cryptoService.decryptMessage(
              lastMsg['content'],
              sharedSecret,
            );
            await updateContactLastMessage(
              contactId,
              lastMessage: decryptedText,
              lastMessageTime: timestamp,
              isLastMsgDecrypted: true,
              lastMessageId: messageId,
            );
          } catch (e) {
            print("Error decrypting last message: $e");
            await updateContactLastMessage(
              contactId,
              lastMessage: lastMsg['content50'] ?? 'Зашифрованное сообщение',
              lastMessageTime: timestamp,
              isLastMsgDecrypted: false,
              lastMessageId: messageId,
            );
          }
        } else {
          await updateContactLastMessage(
            contactId,
            lastMessage: lastMsg['content50'] ?? 'Зашифрованное сообщение',
            lastMessageTime: timestamp,
            isLastMsgDecrypted: false,
            lastMessageId: messageId,
          );
        }
      } else {
        // Нет сообщений
        await updateContactLastMessage(
          contactId,
          lastMessage: null,
          lastMessageTime: null,
          lastMessageId: null,
        );
      }
    } catch (e) {
      print("Error refreshing contact last message: $e");
    }
  }
}
