import 'package:flutter/foundation.dart';

import '../../../../core/common/utils/json_utils.dart';
import '../../domain/entities/dashboard_kpi.dart';
import '../../domain/entities/dashboard_pending_approval.dart';
import '../../domain/entities/dashboard_summary.dart';
import '../../domain/entities/dashboard_transaction_summary.dart';

/// 대시보드 요약 응답 DTO.
class DashboardSummaryDto {
  const DashboardSummaryDto({
    this.generatedAt,
    this.kpis = const [],
    this.recentTransactions = const [],
    this.pendingApprovals = const [],
  });

  final DateTime? generatedAt;
  final List<DashboardKpiDto> kpis;
  final List<DashboardTransactionDto> recentTransactions;
  final List<DashboardApprovalDto> pendingApprovals;

  factory DashboardSummaryDto.fromJson(Map<String, dynamic> json) {
    final generatedAt = _parseDate(json['generated_at']);
    final kpiList = JsonUtils.extractList(
      json,
      keys: const ['kpis'],
    ).map(DashboardKpiDto.fromJson).toList(growable: false);
    final transactionList = JsonUtils.extractList(
      json,
      keys: const ['recent_transactions'],
    ).map(DashboardTransactionDto.fromJson).toList(growable: false);
    final approvalList = JsonUtils.extractList(
      json,
      keys: const ['pending_approvals'],
    ).map(DashboardApprovalDto.fromJson).toList(growable: false);

    return DashboardSummaryDto(
      generatedAt: generatedAt,
      kpis: kpiList,
      recentTransactions: transactionList,
      pendingApprovals: approvalList,
    );
  }

  DashboardSummary toEntity() {
    return DashboardSummary(
      generatedAt: generatedAt,
      kpis: kpis.map((dto) => dto.toEntity()).toList(growable: false),
      recentTransactions: recentTransactions
          .map((dto) => dto.toEntity())
          .toList(growable: false),
      pendingApprovals: pendingApprovals
          .map((dto) => dto.toEntity())
          .toList(growable: false),
    );
  }
}

class DashboardKpiDto {
  const DashboardKpiDto({
    required this.key,
    required this.label,
    required this.value,
    this.trendLabel,
    this.delta,
  });

  final String key;
  final String label;
  final num value;
  final String? trendLabel;
  final double? delta;

  factory DashboardKpiDto.fromJson(Map<String, dynamic> json) {
    final key = _readString(json, 'key') ?? '';
    final label = _readString(json, 'label') ?? key;
    final value = _readNum(json, 'value');
    final trendLabel = _readString(json, 'trend_label');
    final delta = _readDouble(json, 'delta');
    return DashboardKpiDto(
      key: key,
      label: label,
      value: value ?? 0,
      trendLabel: trendLabel,
      delta: delta,
    );
  }

  DashboardKpi toEntity() {
    return DashboardKpi(
      key: key,
      label: label,
      value: value,
      trendLabel: trendLabel,
      delta: delta,
    );
  }
}

class DashboardTransactionDto {
  const DashboardTransactionDto({
    required this.transactionNo,
    required this.transactionDate,
    required this.transactionType,
    required this.statusName,
    required this.createdBy,
  });

  final String transactionNo;
  final String transactionDate;
  final String transactionType;
  final String statusName;
  final String createdBy;

  factory DashboardTransactionDto.fromJson(Map<String, dynamic> json) {
    return DashboardTransactionDto(
      transactionNo: _readString(json, 'transaction_no') ?? '',
      transactionDate: _readString(json, 'transaction_date') ?? '',
      transactionType: _readString(json, 'transaction_type') ?? '',
      statusName: _readString(json, 'status_name') ?? '',
      createdBy: _readString(json, 'created_by') ?? '',
    );
  }

  DashboardTransactionSummary toEntity() {
    return DashboardTransactionSummary(
      transactionNo: transactionNo,
      transactionDate: transactionDate,
      transactionType: transactionType,
      statusName: statusName,
      createdBy: createdBy,
    );
  }
}

class DashboardApprovalDto {
  const DashboardApprovalDto({
    this.approvalId,
    required this.approvalNo,
    required this.title,
    required this.stepSummary,
    this.requestedAt,
  });

  final int? approvalId;
  final String approvalNo;
  final String title;
  final String stepSummary;
  final DateTime? requestedAt;

  factory DashboardApprovalDto.fromJson(Map<String, dynamic> json) {
    num? rawId = _readNum(json, 'approval_id');
    if (rawId == null) {
      final approvalMap = json['approval'];
      if (approvalMap is Map<String, dynamic>) {
        rawId = _readNum(approvalMap, 'id');
        if (rawId == null && approvalMap.containsKey('id')) {
          final fallbackValue = approvalMap['id'];
          debugPrint(
            '[DashboardSummaryDto] approval.id 파싱 실패: runtimeType=${fallbackValue.runtimeType}, value=$fallbackValue',
          );
        }
      }
    }
    final approvalIdValue = rawId?.toInt();
    if (approvalIdValue == null && json.containsKey('approval_id')) {
      final rawValue = json['approval_id'];
      debugPrint(
        '[DashboardSummaryDto] approval_id 파싱 실패: runtimeType=${rawValue.runtimeType}, value=$rawValue',
      );
    }
    return DashboardApprovalDto(
      approvalId: approvalIdValue,
      approvalNo: _readString(json, 'approval_no') ?? '',
      title: _readString(json, 'title') ?? '',
      stepSummary: _readString(json, 'step_summary') ?? '',
      requestedAt: _parseDate(json['requested_at']),
    );
  }

  DashboardPendingApproval toEntity() {
    return DashboardPendingApproval(
      approvalId: approvalId,
      approvalNo: approvalNo,
      title: title,
      stepSummary: stepSummary,
      requestedAt: requestedAt,
    );
  }
}

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

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

num? _readNum(Map<String, dynamic>? source, String key) {
  if (source == null) return null;
  final value = source[key];
  if (value is num) {
    return value;
  }
  if (value is String) {
    final trimmed = value.trim();
    if (trimmed.isEmpty) {
      return null;
    }
    return num.tryParse(trimmed);
  }
  return null;
}

double? _readDouble(Map<String, dynamic>? source, String key) {
  final value = _readNum(source, key);
  if (value == null) {
    return null;
  }
  return value.toDouble();
}
