enum MessageType {
  text,
  file,
  image,
  system;

  static MessageType fromString(String? value) {
    switch (value?.toUpperCase()) {
      case 'FILE':
        return MessageType.file;
      case 'IMAGE':
        return MessageType.image;
      case 'SYSTEM':
        return MessageType.system;
      default:
        return MessageType.text;
    }
  }

  String toApiString() => name.toUpperCase();
}

enum MessageStatus {
  sent,
  delivered,
  read;

  static MessageStatus fromString(String? value) {
    switch (value?.toUpperCase()) {
      case 'DELIVERED':
        return MessageStatus.delivered;
      case 'READ':
        return MessageStatus.read;
      default:
        return MessageStatus.sent;
    }
  }
}

class OtherParty {
  final String id;
  final String? userId;
  final String name;
  final String? avatar;
  final String? headline;
  final bool isOnline;
  final String? lastSeenAt;

  const OtherParty({
    required this.id,
    this.userId,
    required this.name,
    this.avatar,
    this.headline,
    this.isOnline = false,
    this.lastSeenAt,
  });

  factory OtherParty.fromJson(Map<String, dynamic> json) {
    return OtherParty(
      id: json['id'] as String,
      userId: json['userId'] as String?,
      name: json['name'] as String? ?? '',
      avatar: json['avatar'] as String?,
      headline: json['headline'] as String?,
      isOnline: json['isOnline'] as bool? ?? false,
      lastSeenAt: json['lastSeenAt'] as String?,
    );
  }

  OtherParty copyWith({bool? isOnline, String? lastSeenAt}) {
    return OtherParty(
      id: id,
      userId: userId,
      name: name,
      avatar: avatar,
      headline: headline,
      isOnline: isOnline ?? this.isOnline,
      lastSeenAt: lastSeenAt ?? this.lastSeenAt,
    );
  }
}

class Conversation {
  final String id;
  final String userId;
  final String agentProfileId;
  final String? lastMessageAt;
  final String? lastMessageText;
  final int userUnreadCount;
  final int agentUnreadCount;
  final int unreadCount;
  final String createdAt;
  final String updatedAt;
  final OtherParty otherParty;
  final List<ChatMessage>? messages;

  const Conversation({
    required this.id,
    required this.userId,
    required this.agentProfileId,
    this.lastMessageAt,
    this.lastMessageText,
    this.userUnreadCount = 0,
    this.agentUnreadCount = 0,
    this.unreadCount = 0,
    required this.createdAt,
    required this.updatedAt,
    required this.otherParty,
    this.messages,
  });

  factory Conversation.fromJson(Map<String, dynamic> json) {
    return Conversation(
      id: json['id'] as String,
      userId: json['userId'] as String,
      agentProfileId: json['agentProfileId'] as String,
      lastMessageAt: json['lastMessageAt'] as String?,
      lastMessageText: json['lastMessageText'] as String?,
      userUnreadCount: json['userUnreadCount'] as int? ?? 0,
      agentUnreadCount: json['agentUnreadCount'] as int? ?? 0,
      unreadCount: json['unreadCount'] as int? ?? 0,
      createdAt: json['createdAt'] as String,
      updatedAt: json['updatedAt'] as String,
      otherParty:
          OtherParty.fromJson(json['otherParty'] as Map<String, dynamic>),
      messages: (json['messages'] as List<dynamic>?)
          ?.map((e) => ChatMessage.fromJson(e as Map<String, dynamic>))
          .toList(),
    );
  }

  Conversation copyWith({
    int? unreadCount,
    String? lastMessageAt,
    String? lastMessageText,
    OtherParty? otherParty,
    List<ChatMessage>? messages,
  }) {
    return Conversation(
      id: id,
      userId: userId,
      agentProfileId: agentProfileId,
      lastMessageAt: lastMessageAt ?? this.lastMessageAt,
      lastMessageText: lastMessageText ?? this.lastMessageText,
      userUnreadCount: userUnreadCount,
      agentUnreadCount: agentUnreadCount,
      unreadCount: unreadCount ?? this.unreadCount,
      createdAt: createdAt,
      updatedAt: updatedAt,
      otherParty: otherParty ?? this.otherParty,
      messages: messages ?? this.messages,
    );
  }
}

class SenderProfile {
  final String? firstName;
  final String? lastName;
  final String? avatar;

  const SenderProfile({this.firstName, this.lastName, this.avatar});

  factory SenderProfile.fromJson(Map<String, dynamic> json) {
    return SenderProfile(
      firstName: json['firstName'] as String?,
      lastName: json['lastName'] as String?,
      avatar: json['avatar'] as String?,
    );
  }
}

class MessageSender {
  final String id;
  final String role;
  final SenderProfile? userProfile;
  final SenderProfile? agentProfile;

  const MessageSender({
    required this.id,
    required this.role,
    this.userProfile,
    this.agentProfile,
  });

  String get displayName {
    final profile = userProfile ?? agentProfile;
    if (profile == null) return 'Unknown';
    return '${profile.firstName ?? ''} ${profile.lastName ?? ''}'.trim();
  }

  String? get avatar => userProfile?.avatar ?? agentProfile?.avatar;

  factory MessageSender.fromJson(Map<String, dynamic> json) {
    return MessageSender(
      id: json['id'] as String,
      role: json['role'] as String? ?? '',
      userProfile: json['userProfile'] != null
          ? SenderProfile.fromJson(
              json['userProfile'] as Map<String, dynamic>)
          : null,
      agentProfile: json['agentProfile'] != null
          ? SenderProfile.fromJson(
              json['agentProfile'] as Map<String, dynamic>)
          : null,
    );
  }
}

class ChatMessage {
  final String id;
  final String conversationId;
  final String senderId;
  final String content;
  final MessageType messageType;
  final String? fileUrl;
  final String? fileName;
  final int? fileSize;
  final String? mimeType;
  final MessageStatus status;
  final String? deliveredAt;
  final String? readAt;
  final String createdAt;
  final String updatedAt;
  final MessageSender sender;

  const ChatMessage({
    required this.id,
    required this.conversationId,
    required this.senderId,
    required this.content,
    this.messageType = MessageType.text,
    this.fileUrl,
    this.fileName,
    this.fileSize,
    this.mimeType,
    this.status = MessageStatus.sent,
    this.deliveredAt,
    this.readAt,
    required this.createdAt,
    required this.updatedAt,
    required this.sender,
  });

  bool isMine(String currentUserId) => senderId == currentUserId;

  factory ChatMessage.fromJson(Map<String, dynamic> json) {
    return ChatMessage(
      id: json['id'] as String,
      conversationId: json['conversationId'] as String,
      senderId: json['senderId'] as String,
      content: json['content'] as String? ?? '',
      messageType: MessageType.fromString(json['messageType'] as String?),
      fileUrl: json['fileUrl'] as String?,
      fileName: json['fileName'] as String?,
      fileSize: json['fileSize'] as int?,
      mimeType: json['mimeType'] as String?,
      status: MessageStatus.fromString(json['status'] as String?),
      deliveredAt: json['deliveredAt'] as String?,
      readAt: json['readAt'] as String?,
      createdAt: json['createdAt'] as String,
      updatedAt: json['updatedAt'] as String,
      sender: json['sender'] != null
          ? MessageSender.fromJson(json['sender'] as Map<String, dynamic>)
          : MessageSender(id: json['senderId'] as String, role: ''),
    );
  }
}

class PaginationInfo {
  final int page;
  final int limit;
  final int total;
  final int pages;

  const PaginationInfo({
    required this.page,
    required this.limit,
    required this.total,
    required this.pages,
  });

  bool get hasMore => page < pages;

  factory PaginationInfo.fromJson(Map<String, dynamic> json) {
    return PaginationInfo(
      page: json['page'] as int? ?? 1,
      limit: json['limit'] as int? ?? 50,
      total: json['total'] as int? ?? 0,
      pages: json['pages'] as int? ?? 1,
    );
  }
}
