import 'package:votianlt_app/services/developer.dart' as developer;

enum ChatDirection { incoming, outgoing }

enum ChatMessageType { general, jobRelated }

enum ChatContentType { text, image }

ChatDirection chatDirectionFromString(
  String? value, {
  ChatDirection fallback = ChatDirection.incoming,
}) {
  switch (value?.toUpperCase()) {
    case 'CLIENT':
    case 'OUTGOING':
      return ChatDirection.outgoing;
    case 'SERVER':
    case 'INCOMING':
      return ChatDirection.incoming;
    default:
      return fallback;
  }
}

String chatDirectionToString(ChatDirection direction) {
  return direction == ChatDirection.outgoing ? 'CLIENT' : 'SERVER';
}

ChatMessageType chatMessageTypeFromString(
  String? value, {
  ChatMessageType fallback = ChatMessageType.general,
}) {
  switch (value?.toUpperCase()) {
    case 'JOB_RELATED':
      return ChatMessageType.jobRelated;
    case 'GENERAL':
      return ChatMessageType.general;
    default:
      return fallback;
  }
}

String chatMessageTypeToString(ChatMessageType type) {
  return type == ChatMessageType.jobRelated ? 'JOB_RELATED' : 'GENERAL';
}

ChatContentType chatContentTypeFromString(
  String? value, {
  ChatContentType fallback = ChatContentType.text,
}) {
  switch (value?.toUpperCase()) {
    case 'IMAGE':
      return ChatContentType.image;
    case 'TEXT':
      return ChatContentType.text;
    default:
      return fallback;
  }
}

String chatContentTypeToString(ChatContentType type) {
  return type == ChatContentType.image ? 'IMAGE' : 'TEXT';
}

class ChatMessage {
  final String id;
  final String content;
  final DateTime createdAt;
  final ChatDirection direction;
  final ChatMessageType messageType;
  final ChatContentType contentType;
  final String? jobId;
  final String? jobNumber;
  final bool read;
  final bool pendingSync;

  const ChatMessage({
    required this.id,
    required this.content,
    required this.createdAt,
    required this.direction,
    required this.messageType,
    this.contentType = ChatContentType.text,
    this.jobId,
    this.jobNumber,
    this.read = false,
    this.pendingSync = false,
  });

  factory ChatMessage.fromJson(Map<String, dynamic> json) {
    final rawId = (json['messageId'] ?? json['id'] ?? '').toString();
    final rawContent = (json['content'] ?? json['text'] ?? '').toString();
    final rawContentType = json['contentType']?.toString();

    DateTime createdAt;
    final createdAtRaw = json['createdAt'] ?? json['timestamp'];
    if (createdAtRaw is DateTime) {
      createdAt = createdAtRaw;
    } else {
      createdAt =
          DateTime.tryParse(createdAtRaw?.toString() ?? '') ?? DateTime.now();
    }

    var direction = chatDirectionFromString(
      json['origin']?.toString() ?? json['direction']?.toString(),
      fallback:
          json['isOwn'] == true
              ? ChatDirection.outgoing
              : ChatDirection.incoming,
    );

    var messageType = chatMessageTypeFromString(
      json['messageType']?.toString(),
      fallback:
          ((json['jobId']?.toString().isNotEmpty ?? false) ||
                  (json['jobNumber']?.toString().isNotEmpty ?? false))
              ? ChatMessageType.jobRelated
              : ChatMessageType.general,
    );

    final jobIdRaw = json['jobId']?.toString();
    final jobNumberRaw = json['jobNumber']?.toString();
    final jobId = jobIdRaw?.trim();
    final jobNumber = jobNumberRaw?.trim();

    if (rawId.isEmpty || rawContent.isEmpty) {
      developer.log(
        'Invalid ChatMessage payload (one or more required fields missing): $json',
      );
    }

    return ChatMessage(
      id: rawId,
      content: rawContent,
      createdAt: createdAt,
      direction: direction,
      messageType: messageType,
      contentType: chatContentTypeFromString(rawContentType),
      jobId: jobId?.isEmpty ?? true ? null : jobId,
      jobNumber: jobNumber?.isEmpty ?? true ? null : jobNumber,
      read: json['read'] == true,
      pendingSync: json['pendingSync'] == true,
    );
  }

  Map<String, dynamic> toJson() {
    final map = <String, dynamic>{
      'messageId': id,
      'content': content,
      'origin': chatDirectionToString(direction),
      'messageType': chatMessageTypeToString(messageType),
      'contentType': chatContentTypeToString(contentType),
      'createdAt': createdAt.toIso8601String(),
      'read': read,
    };

    if (jobId != null && jobId!.isNotEmpty) {
      map['jobId'] = jobId;
    }
    if (jobNumber != null && jobNumber!.isNotEmpty) {
      map['jobNumber'] = jobNumber;
    }
    if (pendingSync) {
      map['pendingSync'] = true;
    }

    return map;
  }

  bool get isOwn => direction == ChatDirection.outgoing;

  ChatMessage copyWith({
    String? id,
    String? content,
    DateTime? createdAt,
    ChatDirection? direction,
    ChatMessageType? messageType,
    ChatContentType? contentType,
    String? jobId,
    String? jobNumber,
    bool? read,
    bool? pendingSync,
  }) {
    return ChatMessage(
      id: id ?? this.id,
      content: content ?? this.content,
      createdAt: createdAt ?? this.createdAt,
      direction: direction ?? this.direction,
      messageType: messageType ?? this.messageType,
      contentType: contentType ?? this.contentType,
      jobId: jobId ?? this.jobId,
      jobNumber: jobNumber ?? this.jobNumber,
      read: read ?? this.read,
      pendingSync: pendingSync ?? this.pendingSync,
    );
  }

  @override
  String toString() {
    return 'ChatMessage(id: $id, direction: $direction, messageType: $messageType, contentType: $contentType, createdAt: $createdAt)';
  }

  @override
  bool operator ==(Object other) {
    if (identical(this, other)) return true;
    return other is ChatMessage && other.id == id;
  }

  @override
  int get hashCode => id.hashCode;
}
