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

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

/// 고객(Customer) API 응답을 다루는 DTO.
class CustomerDto {
  CustomerDto({
    this.id,
    required this.customerCode,
    required this.customerName,
    this.contactName,
    this.isPartner = false,
    this.isGeneral = true,
    this.email,
    this.mobileNo,
    this.zipcode,
    this.addressDetail,
    this.isActive = true,
    this.isDeleted = false,
    this.note,
    this.createdAt,
    this.updatedAt,
  });

  final int? id;
  final String customerCode;
  final String customerName;
  final String? contactName;
  final bool isPartner;
  final bool isGeneral;
  final String? email;
  final String? mobileNo;
  final CustomerZipcodeDto? zipcode;
  final String? addressDetail;
  final bool isActive;
  final bool isDeleted;
  final String? note;
  final DateTime? createdAt;
  final DateTime? updatedAt;

  /// 원본 JSON으로부터 DTO를 생성한다.
  factory CustomerDto.fromJson(Map<String, dynamic> json) {
    return CustomerDto(
      id: json['id'] as int?,
      customerCode: json['customer_code'] as String,
      customerName: json['customer_name'] as String,
      contactName: json['contact_name'] as String?,
      isPartner: (json['is_partner'] as bool?) ?? false,
      isGeneral: (json['is_general'] as bool?) ?? true,
      email: json['email'] as String?,
      mobileNo: json['mobile_no'] as String?,
      zipcode: json['zipcode'] is Map<String, dynamic>
          ? CustomerZipcodeDto.fromJson(json['zipcode'] as Map<String, dynamic>)
          : null,
      addressDetail: json['address_detail'] as String?,
      isActive: (json['is_active'] as bool?) ?? true,
      isDeleted: (json['is_deleted'] as bool?) ?? false,
      note: json['note'] as String?,
      createdAt: _parseDate(json['created_at']),
      updatedAt: _parseDate(json['updated_at']),
    );
  }

  /// DTO를 JSON 맵으로 변환한다.
  Map<String, dynamic> toJson() {
    return {
      if (id != null) 'id': id,
      'customer_code': customerCode,
      'customer_name': customerName,
      'contact_name': contactName,
      'is_partner': isPartner,
      'is_general': isGeneral,
      'email': email,
      'mobile_no': mobileNo,
      'zipcode': zipcode?.toJson(),
      'address_detail': addressDetail,
      'is_active': isActive,
      'is_deleted': isDeleted,
      'note': note,
      'created_at': createdAt?.toIso8601String(),
      'updated_at': updatedAt?.toIso8601String(),
    };
  }

  /// DTO를 도메인 [Customer] 엔티티로 변환한다.
  Customer toEntity() => Customer(
    id: id,
    customerCode: customerCode,
    customerName: customerName,
    contactName: contactName,
    isPartner: isPartner,
    isGeneral: isGeneral,
    email: email,
    mobileNo: mobileNo,
    zipcode: zipcode?.toEntity(),
    addressDetail: addressDetail,
    isActive: isActive,
    isDeleted: isDeleted,
    note: note,
    createdAt: createdAt,
    updatedAt: updatedAt,
  );

  /// 페이징 응답을 파싱해 [PaginatedResult] 형식으로 반환한다.
  static PaginatedResult<Customer> parsePaginated(Map<String, dynamic>? json) {
    final rawItems = JsonUtils.extractList(json, keys: const ['items']);
    final items = rawItems
        .map(CustomerDto.fromJson)
        .map((dto) => dto.toEntity())
        .toList(growable: false);
    return PaginatedResult<Customer>(
      items: items,
      page: JsonUtils.readInt(json, 'page', fallback: 1),
      pageSize: JsonUtils.readInt(json, 'page_size', fallback: items.length),
      total: JsonUtils.readInt(json, 'total', fallback: items.length),
    );
  }
}

/// 고객 주소의 우편번호 정보를 담는 DTO.
class CustomerZipcodeDto {
  CustomerZipcodeDto({
    required this.zipcode,
    this.sido,
    this.sigungu,
    this.roadName,
  });

  final String zipcode;
  final String? sido;
  final String? sigungu;
  final String? roadName;

  /// JSON에서 우편번호 정보를 파싱한다.
  factory CustomerZipcodeDto.fromJson(Map<String, dynamic> json) {
    return CustomerZipcodeDto(
      zipcode: json['zipcode'] as String,
      sido: json['sido'] as String?,
      sigungu: json['sigungu'] as String?,
      roadName: json['road_name'] as String?,
    );
  }

  /// DTO를 JSON 맵으로 직렬화한다.
  Map<String, dynamic> toJson() {
    return {
      'zipcode': zipcode,
      'sido': sido,
      'sigungu': sigungu,
      'road_name': roadName,
    };
  }

  /// DTO를 [CustomerZipcode] 엔티티로 변환한다.
  CustomerZipcode toEntity() => CustomerZipcode(
    zipcode: zipcode,
    sido: sido,
    sigungu: sigungu,
    roadName: roadName,
  );
}

/// 문자열/DateTime 값을 파싱해 [DateTime]으로 변환한다.
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;
}

/// 고객 입력 모델을 API 요청 바디로 변환한다.
Map<String, dynamic> customerInputToJson(CustomerInput input) {
  final map = input.toPayload();
  map.removeWhere((key, value) => value == null);
  return map;
}
