import '../../domain/entities/chat_message.dart';

class ChatMessageModel {
  final String id;
  final String role;
  final String content;
  final String timestamp;
  final String? type;
  final Map<String, dynamic>? toolExecution;
  final Map<String, dynamic>? approvalRequest;
  final Map<String, dynamic>? metadata;
  final List<Map<String, dynamic>>? attachments;

  const ChatMessageModel({
    required this.id,
    required this.role,
    required this.content,
    required this.timestamp,
    this.type,
    this.toolExecution,
    this.approvalRequest,
    this.metadata,
    this.attachments,
  });

  factory ChatMessageModel.fromJson(Map<String, dynamic> json) {
    return ChatMessageModel(
      id: json['id'] as String? ?? '',
      role: json['role'] as String? ?? 'assistant',
      content: json['content'] as String? ?? json['text'] as String? ?? '',
      timestamp: json['timestamp'] as String? ??
          json['created_at'] as String? ??
          json['createdAt'] as String? ??
          DateTime.now().toIso8601String(),
      type: json['type'] as String?,
      toolExecution: json['tool_execution'] as Map<String, dynamic>? ??
          json['toolExecution'] as Map<String, dynamic>?,
      approvalRequest: json['approval_request'] as Map<String, dynamic>? ??
          json['approvalRequest'] as Map<String, dynamic>?,
      metadata: json['metadata'] as Map<String, dynamic>?,
      attachments: (json['attachments'] as List<dynamic>?)
          ?.map((a) => Map<String, dynamic>.from(a as Map))
          .toList(),
    );
  }

  Map<String, dynamic> toJson() {
    return {
      'id': id,
      'role': role,
      'content': content,
      'timestamp': timestamp,
      if (type != null) 'type': type,
      if (toolExecution != null) 'toolExecution': toolExecution,
      if (approvalRequest != null) 'approvalRequest': approvalRequest,
      if (metadata != null) 'metadata': metadata,
      if (attachments != null) 'attachments': attachments,
    };
  }

  /// Converts this model to a domain [ChatMessage] entity.
  ChatMessage toEntity() {
    return ChatMessage(
      id: id,
      role: _parseRole(role),
      content: content,
      timestamp: DateTime.tryParse(timestamp) ?? DateTime.now(),
      type: _parseType(type),
      toolExecution: toolExecution != null ? _parseToolExecution(toolExecution!) : null,
      approvalRequest: approvalRequest != null ? _parseApprovalRequest(approvalRequest!) : null,
      metadata: metadata,
      attachments: attachments?.map((a) => ChatAttachment(
        base64Data: a['base64Data'] as String? ?? '',
        mediaType: a['mediaType'] as String? ?? 'image/jpeg',
        fileName: a['fileName'] as String?,
      )).toList(),
    );
  }

  /// Creates a model from a domain [ChatMessage] entity.
  factory ChatMessageModel.fromEntity(ChatMessage entity) {
    return ChatMessageModel(
      id: entity.id,
      role: entity.role.name,
      content: entity.content,
      timestamp: entity.timestamp.toIso8601String(),
      type: entity.type?.name,
      toolExecution: entity.toolExecution != null
          ? {
              'toolName': entity.toolExecution!.toolName,
              'input': entity.toolExecution!.input,
              'output': entity.toolExecution!.output,
              'riskLevel': entity.toolExecution!.riskLevel,
              'status': entity.toolExecution!.status.name,
            }
          : null,
      approvalRequest: entity.approvalRequest != null
          ? {
              'taskId': entity.approvalRequest!.taskId,
              'command': entity.approvalRequest!.command,
              'riskLevel': entity.approvalRequest!.riskLevel,
              'targetServer': entity.approvalRequest!.targetServer,
              'expiresAt': entity.approvalRequest!.expiresAt.toIso8601String(),
              'status': entity.approvalRequest!.status,
            }
          : null,
      metadata: entity.metadata,
      attachments: entity.attachments?.map((a) => a.toJson()).toList(),
    );
  }

  static MessageRole _parseRole(String role) {
    switch (role.toLowerCase()) {
      case 'user':
        return MessageRole.user;
      case 'system':
        return MessageRole.system;
      case 'assistant':
      default:
        return MessageRole.assistant;
    }
  }

  static MessageType? _parseType(String? type) {
    if (type == null) return null;
    switch (type.toLowerCase()) {
      case 'tool_use':
      case 'tooluse':
        return MessageType.toolUse;
      case 'tool_result':
      case 'toolresult':
        return MessageType.toolResult;
      case 'approval':
        return MessageType.approval;
      case 'thinking':
        return MessageType.thinking;
      case 'standing_order_draft':
      case 'standingorderdraft':
        return MessageType.standingOrderDraft;
      case 'text':
      default:
        return MessageType.text;
    }
  }

  static ToolExecution _parseToolExecution(Map<String, dynamic> json) {
    return ToolExecution(
      toolName: json['toolName'] as String? ?? json['tool_name'] as String? ?? '',
      input: json['input'] as String? ?? '',
      output: json['output'] as String?,
      riskLevel: json['riskLevel'] as int? ?? json['risk_level'] as int? ?? 0,
      status: _parseToolStatus(json['status'] as String? ?? 'executing'),
    );
  }

  static ToolStatus _parseToolStatus(String status) {
    switch (status.toLowerCase()) {
      case 'completed':
        return ToolStatus.completed;
      case 'error':
        return ToolStatus.error;
      case 'blocked':
        return ToolStatus.blocked;
      case 'awaiting_approval':
      case 'awaitingapproval':
        return ToolStatus.awaitingApproval;
      case 'executing':
      default:
        return ToolStatus.executing;
    }
  }

  static ApprovalRequest _parseApprovalRequest(Map<String, dynamic> json) {
    return ApprovalRequest(
      taskId: json['taskId'] as String? ?? json['task_id'] as String? ?? '',
      command: json['command'] as String? ?? '',
      riskLevel: json['riskLevel'] as int? ?? json['risk_level'] as int? ?? 0,
      targetServer: json['targetServer'] as String? ?? json['target_server'] as String?,
      expiresAt: DateTime.tryParse(
            json['expiresAt'] as String? ?? json['expires_at'] as String? ?? '',
          ) ??
          DateTime.now().add(const Duration(minutes: 5)),
      status: json['status'] as String?,
    );
  }
}
