import 'dart:async';
import '../../../../core/errors/result.dart';
import '../../../../core/network/signalr_service.dart';
import '../../domain/entities/chat.dart';
import '../../domain/entities/message.dart';
import '../../domain/repositories/chat_repository.dart';
import '../datasources/chat_local_datasource.dart';
import '../datasources/chat_remote_datasource.dart';

class ChatRepositoryImpl implements ChatRepository {
  final ChatRemoteDataSource remoteDataSource;
  final ChatLocalDataSource localDataSource;
  final SignalRService signalRService;

  ChatRepositoryImpl({
    required this.remoteDataSource,
    required this.localDataSource,
    required this.signalRService,
  });

  @override
  Stream<Message> get messageStream => signalRService.messages;

  @override
  Stream<Map<String, dynamic>> get typingStream => signalRService.typingUpdates;

  @override
  Stream<Map<String, dynamic>> get statusStream => signalRService.statusUpdates;
  
  @override
  Stream<Map<String, dynamic>> get readReceiptStream => signalRService.readReceipts;

  @override
  Future<void> sendTypingStatus(String chatId, bool isTyping) => signalRService.sendTypingStatus(chatId, isTyping);

  @override
  Future<void> markAsRead(String chatId, String lastReadMessageId, int lastReadSequenceId) => 
      signalRService.markMessagesAsRead(chatId, lastReadMessageId, lastReadSequenceId);

  @override
  Future<void> initSignalR() => signalRService.init();

  @override
  Future<void> disposeSignalR() => signalRService.stop();

  @override
  Future<Result<List<Chat>>> getChats({String? currentUserId}) async {
    // ignore: avoid_print
    print('[DEBUG] ChatRepository.getChats for user: $currentUserId');
    // 1. Return cached chats immediately if available
    final cachedResult = await localDataSource.getCachedChats();
    
    // 2. Fetch from remote and update cache
    final remoteResult = await remoteDataSource.getChats(currentUserId: currentUserId);
    if (remoteResult.isSuccess) {
      final chats = remoteResult.data!;
      // ignore: avoid_print
      print('[DEBUG] Remote getChats success: ${chats.length} chats');
      await localDataSource.cacheChats(chats);
      return Result.success(chats);
    }
    
    // ignore: avoid_print
    print('[DEBUG] Remote getChats failed or empty');
    // If remote fails, return cached or error
    return cachedResult;
  }

  @override
  Future<Result<Chat>> getChatById(String chatId) async {
    final remoteResult = await remoteDataSource.getChatById(chatId);
    if (remoteResult.isSuccess) {
      await localDataSource.cacheChat(remoteResult.data!);
      return remoteResult;
    }
    return localDataSource.getChatFromCache(chatId);
  }

  @override
  Future<Result<Chat>> createPersonalChat(String userId) async {
    final result = await remoteDataSource.createPersonalChat(userId);
    if (result.isSuccess) {
      await localDataSource.cacheChat(result.data!);
    }
    return result;
  }

  @override
  Future<Result<Chat>> createGroupChat(String name, List<String> memberIds) async {
    final result = await remoteDataSource.createGroupChat(name, memberIds);
    if (result.isSuccess) {
      await localDataSource.cacheChat(result.data!);
    }
    return result;
  }

  @override
  Future<Result<Chat>> getOrCreateFavorites() async {
    final result = await remoteDataSource.getOrCreateFavorites();
    if (result.isSuccess) {
      await localDataSource.cacheChat(result.data!);
    }
    return result;
  }

  @override
  Future<Result<Message>> sendMessage(String chatId, String content, {String? type}) async {
    final result = await remoteDataSource.sendMessage(chatId, content, type: type);
    if (result.isSuccess) {
      // We don't cache individual messages here usually, 
      // let SignalR ReceiveMessage handle it or update list
      final messagesResult = await getMessages(chatId);
      if (messagesResult.isSuccess) {
        await localDataSource.cacheMessages(chatId, messagesResult.data!);
      }
    }
    return result;
  }

  @override
  Future<Result<List<Message>>> getMessages(String chatId, {String? cursor}) async {
    // ignore: avoid_print
    print('[DEBUG] ChatRepository.getMessages for chat: $chatId');
    if (cursor == null) {
      final cached = await localDataSource.getMessagesFromCache(chatId);
      final remote = await remoteDataSource.getMessages(chatId);
      if (remote.isSuccess) {
        // ignore: avoid_print
        print('[DEBUG] Remote getMessages success: ${remote.data!.length} messages');
        await localDataSource.cacheMessages(chatId, remote.data!);
        return remote;
      }
      // ignore: avoid_print
      print('[DEBUG] Remote getMessages failed: ${remote.error?.message}');
      return cached;
    } else {
      return remoteDataSource.getMessages(chatId, cursor: cursor);
    }
  }

  @override
  Future<Result<void>> togglePin(String chatId) async {
    final result = await remoteDataSource.togglePin(chatId);
    if (result.isSuccess) {
      final chat = await getChatById(chatId);
      if (chat.isSuccess) {
        await localDataSource.cacheChat(chat.data!);
      }
    }
    return result;
  }

  @override
  Future<Result<void>> clearChat(String chatId) async {
    final result = await remoteDataSource.clearChat(chatId);
    if (result.isSuccess) {
      await localDataSource.cacheMessages(chatId, []);
    }
    return result;
  }

  @override
  Future<Result<void>> clearCache() => localDataSource.clearCache();
}
