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 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?, ); } } 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? 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 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), messages: (json['messages'] as List?) ?.map((e) => ChatMessage.fromJson(e as Map)) .toList(), ); } Conversation copyWith({ int? unreadCount, String? lastMessageAt, String? lastMessageText, OtherParty? otherParty, List? 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 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 json) { return MessageSender( id: json['id'] as String, role: json['role'] as String? ?? '', userProfile: json['userProfile'] != null ? SenderProfile.fromJson( json['userProfile'] as Map) : null, agentProfile: json['agentProfile'] != null ? SenderProfile.fromJson( json['agentProfile'] as Map) : 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 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) : 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 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, ); } }