import '../../../../core/network/api_client.dart';
import '../../../../core/errors/result.dart';
import '../../../../core/errors/errors.dart';
import '../../domain/entities/chat.dart';
import '../../domain/entities/message.dart';
import '../../domain/entities/user.dart';
import 'chat_remote_datasource.dart';

class ChatRemoteDataSourceImpl implements ChatRemoteDataSource {
  final ApiClient apiClient;

  ChatRemoteDataSourceImpl(this.apiClient);

  @override
  Future<Result<List<Chat>>> getChats({String? currentUserId}) async {
    final result = await apiClient.get<List<dynamic>>('/api/chats');
    return result.fold(
      (error) => Result.failure(error),
      (data) {
        try {
          final chats = data.map((json) => _mapChatJson(json, currentUserId: currentUserId)).toList();
          // Sort: favorites first, then by last message time or creation time
          chats.sort((a, b) {
            if (a.type == 'favorites') return -1;
            if (b.type == 'favorites') return 1;
            final timeA = a.lastMessageTime ?? DateTime.fromMillisecondsSinceEpoch(0);
            final timeB = b.lastMessageTime ?? DateTime.fromMillisecondsSinceEpoch(0);
            return timeB.compareTo(timeA);
          });
          return Result.success(chats);
        } catch (e) {
          return Result.failure(AppError.parsing(message: 'Failed to parse chats: $e'));
        }
      },
    );
  }

  @override
  Future<Result<Chat>> getChatById(String chatId) async {
    final result = await apiClient.get<Map<String, dynamic>>('/api/chats/$chatId');
    return result.fold(
      (error) => Result.failure(error),
      (data) {
        try {
          return Result.success(_mapChatJson(data));
        } catch (e) {
          return Result.failure(AppError.parsing(message: 'Failed to parse chat: $e'));
        }
      },
    );
  }

  @override
  Future<Result<Chat>> createPersonalChat(String userId) async {
    final result = await apiClient.post<Map<String, dynamic>>(
      '/api/chats/personal',
      data: {'userId': userId},
    );
    return result.fold(
      (error) => Result.failure(error),
      (data) => Result.success(_mapChatJson(data)),
    );
  }

  @override
  Future<Result<Chat>> createGroupChat(String name, List<String> memberIds) async {
    final result = await apiClient.post<Map<String, dynamic>>(
      '/api/chats/group',
      data: {
        'name': name,
        'memberIds': memberIds,
      },
    );
    return result.fold(
      (error) => Result.failure(error),
      (data) => Result.success(_mapChatJson(data)),
    );
  }

  @override
  Future<Result<Chat>> getOrCreateFavorites() async {
    final result = await apiClient.post<Map<String, dynamic>>('/api/chats/favorites');
    return result.fold(
      (error) => Result.failure(error),
      (data) => Result.success(_mapChatJson(data)),
    );
  }

  @override
  Future<Result<Message>> sendMessage(String chatId, String content, {String? type, List<Map<String, dynamic>>? attachments}) async {
    final result = await apiClient.post<Map<String, dynamic>>(
      '/api/messages/chat/$chatId',
      data: {
        'content': content,
        'type': type ?? 'Text',
        'attachments': attachments,
      },
    );
    return result.fold(
      (error) => Result.failure(error),
      (data) {
        try {
          return Result.success(_mapMessageJson(data));
        } catch (e) {
          return Result.failure(AppError.parsing(message: 'Failed to parse message: $e'));
        }
      },
    );
  }

  @override
  Future<Result<List<Message>>> getMessages(String chatId, {String? cursor}) async {
    final result = await apiClient.get<List<dynamic>>(
      '/api/messages/chat/$chatId',
      queryParameters: cursor != null ? {'cursor': cursor} : null,
    );
    return result.fold(
      (error) => Result.failure(error),
      (data) {
        try {
          return Result.success(data.map((json) => _mapMessageJson(json)).toList());
        } catch (e) {
          return Result.failure(AppError.parsing(message: 'Failed to parse messages: $e'));
        }
      },
    );
  }

  @override
  Future<Result<void>> togglePin(String chatId) async {
    return await apiClient.post('/api/chats/$chatId/pin');
  }

  @override
  Future<Result<void>> clearChat(String chatId) async {
    return await apiClient.post('/api/chats/$chatId/clear');
  }

  Chat _mapChatJson(Map<String, dynamic> json, {String? currentUserId}) {
    final membersData = json['members'] ?? json['participants'];
    final members = (membersData as List<dynamic>?)?.map((m) {
      final userData = m is Map<String, dynamic> ? (m['user'] ?? m) : m;
      return User(
        id: (m is Map ? m['userId'] : null) ?? (userData?['id'] ?? ''),
        name: userData?['displayName'] ?? (userData?['name'] ?? ''),
        avatarUrl: userData?['avatar'] ?? userData?['avatarUrl'],
        isOnline: userData?['isOnline'] ?? userData?['IsOnline'] ?? false,
        lastSeen: _parseDateTime(userData?['lastSeen'] ?? userData?['LastSeen']),
      );
    }).toList();

    dynamic lastMsgRaw = json['lastMessage'];
    if (lastMsgRaw is List && lastMsgRaw.isNotEmpty) {
      lastMsgRaw = lastMsgRaw.first;
    }
    final lastMsgJson = lastMsgRaw ?? (json['messages'] as List?)?.firstOrNull;
    final type = json['type']?.toString().toLowerCase() ?? 'personal';
    
    String title = json['name'] ?? '';
    if (title.isEmpty && type == 'personal' && members != null && members.isNotEmpty) {
      // If personal chat and no title, use the OTHER member's name
      try {
        final otherMember = members.firstWhere(
          (m) => m.id != currentUserId && m.name.isNotEmpty,
          orElse: () => members.firstWhere((m) => m.id != currentUserId, orElse: () => members[0]),
        );
        title = otherMember.name;
      } catch (_) {
        title = members[0].name;
      }
    }

    return Chat(
      id: json['id'],
      type: type,
      title: title,
      avatarUrl: json['avatar'],
      participants: members,
      unreadCount: json['unreadCount'] ?? 0,
      isPinned: json['isPinned'] ?? false,
      lastMessage: lastMsgJson != null && lastMsgJson is Map<String, dynamic> 
          ? _mapMessageJson(lastMsgJson) 
          : null,
      lastMessageTime: lastMsgJson != null && lastMsgJson is Map<String, dynamic> 
          ? _parseDateTime(lastMsgJson['createdAt']) 
          : null,
    );
  }

  Message _mapMessageJson(Map<String, dynamic> json) {
    return Message(
      id: json['id'] ?? '',
      chatId: json['chatId'] ?? '',
      senderId: json['userId'] ?? (json['senderId'] ?? ''),
      content: json['content'] ?? '',
      messageType: json['type']?.toString().toLowerCase() ?? 'text',
      sequenceId: int.tryParse(json['sequenceId']?.toString() ?? '0') ?? 0,
      createdAt: _parseDateTime(json['createdAt']),
      updatedAt: _parseDateTime(json['updatedAt']),
      status: (json['isRead'] ?? false) ? MessageStatus.read : MessageStatus.delivered,
      media: json['media'] is Map<String, dynamic> ? json['media'] as Map<String, dynamic> : null,
    );
  }

  DateTime? _parseDateTime(String? dateStr) {
    if (dateStr == null) return null;
    // If it doesn't have a timezone indicator, assume it's UTC
    String normalized = dateStr;
    if (!normalized.endsWith('Z') && !normalized.contains('+')) {
      normalized += 'Z';
    }
    return DateTime.parse(normalized).toLocal();
  }
}
