import 'package:superport_v2/core/common/utils/json_utils.dart';

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

/// 결재 상태(summary) DTO.
class ApprovalStatusDto {
  ApprovalStatusDto({
    required this.id,
    required this.name,
    this.color,
    bool? isBlockingNext,
    bool? isTerminal,
  }) : isBlockingNext = isBlockingNext ?? true,
       isTerminal = isTerminal ?? false;

  final int id;
  final String name;
  final String? color;
  final bool isBlockingNext;
  final bool isTerminal;

  factory ApprovalStatusDto.fromJson(Map<String, dynamic> json) {
    if (json['status'] is Map<String, dynamic>) {
      return ApprovalStatusDto.fromJson(json['status'] as Map<String, dynamic>);
    }
    final resolvedName =
        _readString(json, 'name') ??
        _readString(json, 'status_name') ??
        _readString(json, 'statusName') ??
        '-';
    final rawColor =
        _readString(json, 'color') ??
        _readString(json, 'status_color') ??
        _readString(json, 'statusColor');
    return ApprovalStatusDto(
      id: JsonUtils.readInt(json, 'id', fallback: 0),
      name: resolvedName,
      color: rawColor,
      isBlockingNext:
          _readBool(json, 'is_blocking_next', fallback: true) ??
          _readBool(json, 'isBlockingNext', fallback: true) ??
          true,
      isTerminal:
          _readBool(json, 'is_terminal', fallback: false) ??
          _readBool(json, 'isTerminal', fallback: false) ??
          false,
    );
  }

  ApprovalStatus toEntity() => ApprovalStatus(
    id: id,
    name: name,
    color: color,
    isBlockingNext: isBlockingNext,
    isTerminal: isTerminal,
  );
}

/// 결재 사용자 요약 DTO.
class ApprovalApproverDto {
  ApprovalApproverDto({
    required this.id,
    required this.employeeNo,
    required this.name,
  });

  final int id;
  final String employeeNo;
  final String name;

  factory ApprovalApproverDto.fromJson(Map<String, dynamic> json) {
    final employeeNo =
        _readString(json, 'employee_no') ??
        _readString(json, 'employee_id', fallback: '-');
    return ApprovalApproverDto(
      id: JsonUtils.readInt(json, 'id', fallback: 0),
      employeeNo: employeeNo ?? '-',
      name: _readString(json, 'name', fallback: '-') ?? '-',
    );
  }

  ApprovalApprover toEntity() =>
      ApprovalApprover(id: id, employeeNo: employeeNo, name: name);
}

/// 결재 단계(summary) DTO.
class ApprovalStepDto {
  ApprovalStepDto({
    this.id,
    this.requestId,
    required this.stepOrder,
    this.templateStepId,
    this.approverRole,
    required this.approver,
    required this.status,
    this.assignedAt,
    this.decidedAt,
    this.actionAt,
    this.note,
    this.isDeleted = false,
    this.isOptional = false,
    this.escalationMinutes,
    this.metadata,
  });

  final int? id;
  final int? requestId;
  final int stepOrder;
  final int? templateStepId;
  final String? approverRole;
  final ApprovalApproverDto approver;
  final ApprovalStatusDto status;
  final DateTime? assignedAt;
  final DateTime? decidedAt;
  final DateTime? actionAt;
  final String? note;
  final bool isDeleted;
  final bool isOptional;
  final int? escalationMinutes;
  final Map<String, dynamic>? metadata;

  factory ApprovalStepDto.fromJson(Map<String, dynamic> json) {
    final statusMap =
        _asMap(json['status']) ?? _asMap(json['step_status']) ?? const {};
    final approverMap = _asMap(json['approver']) ?? const {};

    final assignedAt = _parseDate(json['assigned_at']);
    final decidedAt = _parseDate(json['decided_at']);
    final actionAt = _parseDate(json['action_at']);

    return ApprovalStepDto(
      id: JsonUtils.readInt(json, 'id'),
      requestId: JsonUtils.readInt(json, 'request_id'),
      stepOrder: JsonUtils.readInt(json, 'step_order', fallback: 0),
      templateStepId: JsonUtils.readInt(json, 'template_step_id'),
      approverRole: _readString(json, 'approver_role'),
      approver: ApprovalApproverDto.fromJson(approverMap),
      status: ApprovalStatusDto.fromJson(statusMap),
      assignedAt: assignedAt,
      decidedAt: decidedAt,
      actionAt: actionAt,
      note: _readString(json, 'note'),
      isDeleted:
          _readBool(json, 'is_deleted') ??
          (json['deleted_at'] != null ||
              (json['is_active'] is bool && !(json['is_active'] as bool))),
      isOptional: _readBool(json, 'is_optional', fallback: false) ?? false,
      escalationMinutes: JsonUtils.readInt(json, 'escalation_minutes'),
      metadata: _asMap(
        json['metadata'],
      )?.map((key, value) => MapEntry(key, value)),
    );
  }

  ApprovalStep toEntity() => ApprovalStep(
    id: id,
    requestId: requestId,
    stepOrder: stepOrder,
    templateStepId: templateStepId,
    approverRole: approverRole,
    approver: approver.toEntity(),
    status: status.toEntity(),
    assignedAt: assignedAt ?? DateTime.now(),
    decidedAt: decidedAt,
    actionAt: actionAt,
    note: note,
    isDeleted: isDeleted,
    isOptional: isOptional,
    escalationMinutes: escalationMinutes,
    metadata: metadata,
  );
}

String? _readString(
  Map<String, dynamic>? source,
  String key, {
  String? fallback,
}) {
  if (source == null) return fallback;
  final value = source[key];
  if (value is String) return value;
  if (value == null) return fallback;
  return value.toString();
}

bool? _readBool(Map<String, dynamic>? source, String key, {bool? fallback}) {
  if (source == null) return fallback;
  final value = source[key];
  if (value is bool) return value;
  if (value is num) return value != 0;
  if (value is String) {
    final normalized = value.trim().toLowerCase();
    if (normalized.isEmpty) return fallback;
    return ['1', 'y', 'yes', 'true'].contains(normalized);
  }
  return fallback;
}

Map<String, dynamic>? _asMap(dynamic value) =>
    value is Map<String, dynamic> ? value : null;

DateTime? _parseDate(Object? value) {
  if (value == null) return null;
  if (value is DateTime) return value;
  if (value is String) return DateTime.tryParse(value);
  return null;
}
