import 'dart:async';
import 'package:signalr_netcore/signalr_client.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../../features/chat/domain/entities/message.dart';

class SignalRService {
  final SharedPreferences prefs;
  HubConnection? _hubConnection;
  final _messageController = StreamController<Message>.broadcast();
  final _typingController = StreamController<Map<String, dynamic>>.broadcast();
  final _statusController = StreamController<Map<String, dynamic>>.broadcast();
  final _readReceiptController = StreamController<Map<String, dynamic>>.broadcast();
  
  Stream<Message> get messages => _messageController.stream;
  Stream<Map<String, dynamic>> get typingUpdates => _typingController.stream;
  Stream<Map<String, dynamic>> get statusUpdates => _statusController.stream;
  Stream<Map<String, dynamic>> get readReceipts => _readReceiptController.stream;

  SignalRService(this.prefs);

  Future<void> init() async {
    if (_hubConnection?.state == HubConnectionState.Connected || 
        _hubConnection?.state == HubConnectionState.Connecting) {
      // ignore: avoid_print
      print('[SignalR] Connection already active or connecting. Skipping init.');
      return;
    }
    
    if (_hubConnection != null) {
      await stop();
    }
    final apiUrl = prefs.getString('api_url') ?? 'https://api.messenger.app';
    final token = prefs.getString('access_token');
    
    if (token == null) return;

    final hubUrl = '${apiUrl.replaceAll(RegExp(r'/+$'), '')}/hubs/chat';
    // ignore: avoid_print
    print('[SignalR] Initializing connection to: $hubUrl');
    
    _hubConnection = HubConnectionBuilder()
        .withUrl(hubUrl, options: HttpConnectionOptions(
          accessTokenFactory: () async => token,
        ))
        .withAutomaticReconnect()
        .build();

    _hubConnection?.onclose(({error}) {
      // ignore: avoid_print
      print('[SignalR] Connection closed. Error: $error');
    });

    _hubConnection?.onreconnecting(({error}) {
      // ignore: avoid_print
      print('[SignalR] Reconnecting... Error: $error');
    });

    _hubConnection?.onreconnected(({connectionId}) {
      // ignore: avoid_print
      print('[SignalR] Reconnected! ID: $connectionId');
    });

    // Event names verified from backend source code (MessageNotifier.cs)
    _hubConnection?.on('new_message', _handleReceiveMessage);
    _hubConnection?.on('new_message_received', _handleReceiveMessage); // Optional fallback
    
    _hubConnection?.on('user_typing', _handleUserTyping);
    _hubConnection?.on('user_stopped_typing', _handleUserStoppedTyping);
    _hubConnection?.on('user_online', (args) {
      // ignore: avoid_print
      print('[SignalR] user_online: $args');
      if (args != null && args.isNotEmpty) {
        final data = args[0] as Map<String, dynamic>;
        _statusController.add({'userId': data['userId'] ?? data['UserId'], 'isOnline': true});
      }
    });
    _hubConnection?.on('user_offline', (args) {
      // ignore: avoid_print
      print('[SignalR] user_offline: $args');
      if (args != null && args.isNotEmpty) {
        final data = args[0] as Map<String, dynamic>;
        _statusController.add({
          'userId': data['userId'] ?? data['UserId'], 
          'isOnline': false, 
          'lastSeen': data['lastSeen'] ?? data['LastSeen']
        });
      }
    });
    
    _hubConnection?.on('messages_read', (args) {
      // ignore: avoid_print
      print('[SignalR] messages_read: $args');
      if (args != null && args.isNotEmpty) {
        final data = args[0] as Map<String, dynamic>;
        _readReceiptController.add({
          'chatId': data['chatId'] ?? data['ChatId'],
          'userId': data['userId'] ?? data['UserId'],
          'lastReadMessageId': data['lastReadMessageId'] ?? data['LastReadMessageId'],
          'lastReadSequenceId': data['lastReadSequenceId'] ?? data['LastReadSequenceId'],
        });
      }
    });
    
    try {
      // ignore: avoid_print
      print('[SignalR] Starting connection...');
      await _hubConnection?.start();
      // ignore: avoid_print
      print('[SignalR] Connection started successfully. State: ${_hubConnection?.state}');
    } catch (e) {
      // ignore: avoid_print
      print('[SignalR] Connection failed: $e');
    }
  }

  Future<void> markMessagesAsRead(String chatId, String lastReadMessageId, int lastReadSequenceId) async {
    // ignore: avoid_print
    print('[SignalR] markMessagesAsRead: chatId=$chatId, msgId=$lastReadMessageId, seqId=$lastReadSequenceId');
    await _hubConnection?.invoke('read_messages', args: [
      {
        'ChatId': chatId,
        'LastReadMessageId': lastReadMessageId,
        'LastReadSequenceId': lastReadSequenceId,
      }
    ]);
  }

  void _handleUserTyping(List<dynamic>? arguments) {
    // ignore: avoid_print
    print('[SignalR] _handleUserTyping: $arguments');
    if (arguments != null && arguments.isNotEmpty) {
      final data = arguments[0] as Map<String, dynamic>;
      _typingController.add({'chatId': data['ChatId'] ?? data['chatId'], 'userId': data['UserId'] ?? data['userId'], 'isTyping': true});
    }
  }

  void _handleUserStoppedTyping(List<dynamic>? arguments) {
    // ignore: avoid_print
    print('[SignalR] _handleUserStoppedTyping: $arguments');
    if (arguments != null && arguments.isNotEmpty) {
      final data = arguments[0] as Map<String, dynamic>;
      _typingController.add({'chatId': data['ChatId'] ?? data['chatId'], 'userId': data['UserId'] ?? data['userId'], 'isTyping': false});
    }
  }

  Future<void> sendTypingStatus(String chatId, bool isTyping) async {
    if (isTyping) {
      await _hubConnection?.invoke('typing_start', args: [chatId]);
    } else {
      await _hubConnection?.invoke('typing_stop', args: [chatId]);
    }
  }

  void _handleReceiveMessage(List<dynamic>? arguments) {
    // ignore: avoid_print
    print('[SignalR] _handleReceiveMessage: $arguments');
    if (arguments != null && arguments.isNotEmpty) {
      final data = arguments[0] as Map<String, dynamic>;
      final message = Message(
        id: (data['id'] ?? data['Id'] ?? '').toString(),
        chatId: (data['chatId'] ?? data['ChatId'] ?? '').toString(),
        senderId: (data['senderId'] ?? data['SenderId'] ?? data['userId'] ?? data['UserId'] ?? '').toString(),
        content: data['content'] ?? data['Content'] ?? '',
        messageType: (data['type'] ?? data['Type'] ?? 'text').toString().toLowerCase(),
        sequenceId: int.tryParse((data['sequenceId'] ?? data['SequenceId'] ?? '0').toString()) ?? 0,
        createdAt: _parseDateTime(data['createdAt'] ?? data['CreatedAt']),
        updatedAt: _parseDateTime(data['updatedAt'] ?? data['UpdatedAt']),
        status: (data['isRead'] ?? data['IsRead'] ?? false) ? MessageStatus.read : MessageStatus.delivered,
        media: (data['media'] ?? data['Media']) is Map<String, dynamic> 
            ? (data['media'] ?? data['Media']) as Map<String, dynamic> 
            : null,
      );
      _messageController.add(message);
    }
  }

  DateTime? _parseDateTime(String? dateStr) {
    if (dateStr == null) return null;
    String normalized = dateStr;
    if (!normalized.endsWith('Z') && !normalized.contains('+')) {
      normalized += 'Z';
    }
    return DateTime.parse(normalized).toLocal();
  }

  Future<void> stop() async {
    await _hubConnection?.stop();
    _hubConnection = null;
  }
}
