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

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

/// 제품(Product) API 응답을 표현하는 DTO.
class ProductDto {
  ProductDto({
    this.id,
    required this.productCode,
    required this.productName,
    this.vendor,
    this.uom,
    this.isActive = true,
    this.isDeleted = false,
    this.note,
    this.createdAt,
    this.updatedAt,
  });

  final int? id;
  final String productCode;
  final String productName;
  final ProductVendorDto? vendor;
  final ProductUomDto? uom;
  final bool isActive;
  final bool isDeleted;
  final String? note;
  final DateTime? createdAt;
  final DateTime? updatedAt;

  /// JSON에서 제품 정보를 파싱한다.
  factory ProductDto.fromJson(Map<String, dynamic> json) {
    return ProductDto(
      id: json['id'] as int?,
      productCode: json['product_code'] as String,
      productName: json['product_name'] as String,
      vendor: json['vendor'] is Map<String, dynamic>
          ? ProductVendorDto.fromJson(json['vendor'] as Map<String, dynamic>)
          : null,
      uom: json['uom'] is Map<String, dynamic>
          ? ProductUomDto.fromJson(json['uom'] as Map<String, dynamic>)
          : null,
      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,
      'product_code': productCode,
      'product_name': productName,
      'vendor': vendor?.toJson(),
      'uom': uom?.toJson(),
      'is_active': isActive,
      'is_deleted': isDeleted,
      'note': note,
      'created_at': createdAt?.toIso8601String(),
      'updated_at': updatedAt?.toIso8601String(),
    };
  }

  /// DTO를 도메인 [Product] 엔티티로 변환한다.
  Product toEntity() => Product(
    id: id,
    productCode: productCode,
    productName: productName,
    vendor: vendor?.toEntity(),
    uom: uom?.toEntity(),
    isActive: isActive,
    isDeleted: isDeleted,
    note: note,
    createdAt: createdAt,
    updatedAt: updatedAt,
  );

  /// 엔티티 값을 DTO로 역변환한다.
  static ProductDto fromEntity(Product entity) => ProductDto(
    id: entity.id,
    productCode: entity.productCode,
    productName: entity.productName,
    vendor: entity.vendor == null
        ? null
        : ProductVendorDto(
            id: entity.vendor!.id,
            vendorCode: entity.vendor!.vendorCode,
            vendorName: entity.vendor!.vendorName,
          ),
    uom: entity.uom == null
        ? null
        : ProductUomDto(id: entity.uom!.id, uomName: entity.uom!.uomName),
    isActive: entity.isActive,
    isDeleted: entity.isDeleted,
    note: entity.note,
    createdAt: entity.createdAt,
    updatedAt: entity.updatedAt,
  );

  /// 페이징 응답을 [PaginatedResult]로 변환한다.
  static PaginatedResult<Product> parsePaginated(Map<String, dynamic>? json) {
    final rawItems = JsonUtils.extractList(json, keys: const ['items']);
    final items = rawItems
        .map(ProductDto.fromJson)
        .map((dto) => dto.toEntity())
        .toList(growable: false);
    return PaginatedResult<Product>(
      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 ProductVendorDto {
  ProductVendorDto({
    required this.id,
    required this.vendorCode,
    required this.vendorName,
  });

  final int id;
  final String vendorCode;
  final String vendorName;

  /// JSON에서 공급업체 정보를 파싱한다.
  factory ProductVendorDto.fromJson(Map<String, dynamic> json) {
    return ProductVendorDto(
      id: json['id'] as int,
      vendorCode: json['vendor_code'] as String,
      vendorName: json['vendor_name'] as String,
    );
  }

  /// DTO를 JSON 맵으로 직렬화한다.
  Map<String, dynamic> toJson() {
    return {'id': id, 'vendor_code': vendorCode, 'vendor_name': vendorName};
  }

  /// DTO를 [ProductVendor] 엔티티로 변환한다.
  ProductVendor toEntity() =>
      ProductVendor(id: id, vendorCode: vendorCode, vendorName: vendorName);
}

/// 제품의 단위(UOM) 정보를 담는 DTO.
class ProductUomDto {
  ProductUomDto({required this.id, required this.uomName});

  final int id;
  final String uomName;

  /// JSON에서 단위 정보를 파싱한다.
  factory ProductUomDto.fromJson(Map<String, dynamic> json) {
    return ProductUomDto(
      id: json['id'] as int,
      uomName: json['uom_name'] as String,
    );
  }

  /// DTO를 JSON 맵으로 직렬화한다.
  Map<String, dynamic> toJson() {
    return {'id': id, 'uom_name': uomName};
  }

  /// DTO를 [ProductUom] 엔티티로 변환한다.
  ProductUom toEntity() => ProductUom(id: id, uomName: uomName);
}

/// 문자열/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> productInputToJson(ProductInput input) {
  final map = input.toPayload();
  map.removeWhere((key, value) => value == null);
  return map;
}
