import 'package:json_annotation/json_annotation.dart';
import 'package:niogu_ecommerce_v1/core/enums/approval_process.dart';
import 'package:niogu_ecommerce_v1/core/enums/delivery_fee_type.dart';
import 'package:niogu_ecommerce_v1/core/enums/delivery_type.dart';
import 'package:niogu_ecommerce_v1/core/enums/order_status.dart';
import 'package:niogu_ecommerce_v1/core/utils/converter.dart';
import 'package:niogu_ecommerce_v1/features/checkout/domain/entities/checkout.dart';
import 'package:niogu_ecommerce_v1/features/order/domain/entities/order.dart';

part 'order_model.g.dart';

@JsonSerializable()
class OrderReportResponse {
  final String id;

  @JsonKey(name: 'order_number')
  final String orderNumber;

  @JsonKey(name: 'total_items')
  final int totalItems;

  @JsonKey(name: 'product_images')
  final List<String?> productImages;

  @JsonKey(name: 'total_amount', fromJson: toDouble)
  final double totalAmount;

  @JsonKey(name: 'order_status')
  final String orderStatus;

  @JsonKey(name: 'delivery_type')
  final String deliveryType;

  @JsonKey(name: 'has_been_assessed', defaultValue: false)
  final bool hasBeenAssessed;

  @JsonKey(name: 'created_at')
  final String createdAt;

  const OrderReportResponse({
    required this.id,
    required this.orderNumber,
    required this.productImages,
    required this.totalItems,
    required this.totalAmount,
    required this.orderStatus,
    required this.deliveryType,
    required this.hasBeenAssessed,
    required this.createdAt,
  });

  factory OrderReportResponse.fromJson(Map<String, dynamic> json) =>
      _$OrderReportResponseFromJson(json);

  Map<String, dynamic> toJson() => _$OrderReportResponseToJson(this);

  OrderReport toOrderReport() {
    return OrderReport(
      id: id,
      orderNumber: orderNumber,
      productImages: productImages,
      totalItems: totalItems,
      totalAmount: totalAmount,
      orderStatus: OrderStatus.values.byName(orderStatus),
      deliveryType: deliveryType,
      hasBeenAssessed: hasBeenAssessed,
      createdAt: DateTime.parse(createdAt),
    );
  }
}

@JsonSerializable()
class OrderInfoResponse {
  final String id;

  @JsonKey(name: 'order_number')
  final String orderNumber;

  @JsonKey(name: 'created_at')
  final String createdAt;

  @JsonKey(name: 'order_status')
  final String orderStatus;

  @JsonKey(name: 'is_cancellation')
  final bool? isCancellation;

  @JsonKey(name: 'cancellation_accepted')
  final bool? cancellationAccepted;

  @JsonKey(name: 'approval_process')
  final String? approvalProcess;

  @JsonKey(name: 'delivery_type')
  final String deliveryType;

  @JsonKey(name: 'delivery_preference')
  final String deliveryPreference;

  @JsonKey(name: 'outlet_name_snapshot')
  final String outletNameSnapshot;

  @JsonKey(name: 'outlet_address_snapshot')
  final OutletAddressSnapshotResponse? outletAddressSnapshot;

  @JsonKey(name: 'customer_address_snapshot')
  final CustomerAddressSnapshotResponse? customerAddressSnapshot;

  @JsonKey(name: 'order_items')
  final List<OrderItemInfoResponse> orderItems;

  @JsonKey(name: 'payment_method')
  final String paymentMethod;

  @JsonKey(name: 'payment_proof_url')
  final String? paymentProofUrl;

  @JsonKey(name: 'total_order', fromJson: toDouble)
  final double totalOrder;

  @JsonKey(name: 'delivery_fee_type')
  final String? deliveryFeeType;

  @JsonKey(name: 'delivery_fee')
  final double deliveryFee;

  @JsonKey(name: 'total_delivery_fee', fromJson: toDouble)
  final double totalDeliveryFee;

  @JsonKey(name: 'total_amount', fromJson: toDouble)
  final double totalAmount;

  const OrderInfoResponse({
    required this.id,
    required this.orderNumber,
    required this.createdAt,
    required this.orderStatus,
    required this.isCancellation,
    required this.cancellationAccepted,
    required this.approvalProcess,
    required this.deliveryType,
    required this.deliveryPreference,
    required this.outletNameSnapshot,
    required this.outletAddressSnapshot,
    required this.customerAddressSnapshot,
    required this.orderItems,
    required this.paymentMethod,
    required this.paymentProofUrl,
    required this.totalOrder,
    required this.deliveryFeeType,
    required this.deliveryFee,
    required this.totalDeliveryFee,
    required this.totalAmount,
  });

  factory OrderInfoResponse.fromJson(Map<String, dynamic> json) =>
      _$OrderInfoResponseFromJson(json);

  Map<String, dynamic> toJson() => _$OrderInfoResponseToJson(this);

  OrderInfo toOrderInfo() {
    return OrderInfo(
      id: id,
      orderNumber: orderNumber,
      createdAt: DateTime.parse(createdAt),
      orderStatus: OrderStatus.values.byName(orderStatus),
      isCancellation: isCancellation,
      cancellationAccepted: cancellationAccepted,
      approvalProcess: approvalProcess != null
          ? ApprovalProcess.values.byName(approvalProcess!)
          : null,
      deliveryType: DeliveryType.values.byName(deliveryType),
      deliveryPreference: deliveryPreference,
      outletNameSnapshot: outletNameSnapshot,
      outletAddressSnapshot: outletAddressSnapshot?.toOutletAdddressSnapshot(),
      customerAddressSnapshot: customerAddressSnapshot
          ?.toCustomerAddressSnapshot(),
      orderItems: orderItems.map((item) => item.toOrderItemInfo()).toList(),
      paymentMethod: paymentMethod,
      paymentProofUrl: paymentProofUrl,
      totalOrder: totalOrder,
      deliveryFeeType: DeliveryFeeType.values.byName(
        deliveryFeeType ?? 'fixed',
      ),
      deliveryFee: deliveryFee,
      totalDeliveryFee: totalDeliveryFee,
      totalAmount: totalAmount,
    );
  }
}

@JsonSerializable()
class OutletAddressSnapshotResponse {
  @JsonKey(name: 'full_address')
  final String fullAddress;

  @JsonKey(fromJson: toDouble)
  final double latitude;

  @JsonKey(fromJson: toDouble)
  final double longitude;

  const OutletAddressSnapshotResponse({
    required this.fullAddress,
    required this.latitude,
    required this.longitude,
  });

  factory OutletAddressSnapshotResponse.fromJson(Map<String, dynamic> json) =>
      _$OutletAddressSnapshotResponseFromJson(json);

  Map<String, dynamic> toJson() => _$OutletAddressSnapshotResponseToJson(this);

  OutletAddressSnapshot toOutletAdddressSnapshot() {
    return OutletAddressSnapshot(
      fullAddress: fullAddress,
      latitude: latitude,
      longitude: longitude,
    );
  }
}

@JsonSerializable()
class CustomerAddressSnapshotResponse {
  final String label;

  @JsonKey(name: 'full_address')
  final String fullAddress;

  @JsonKey(fromJson: toDouble)
  final double latitude;

  @JsonKey(fromJson: toDouble)
  final double longitude;

  const CustomerAddressSnapshotResponse({
    required this.label,
    required this.fullAddress,
    required this.latitude,
    required this.longitude,
  });

  factory CustomerAddressSnapshotResponse.fromJson(Map<String, dynamic> json) =>
      _$CustomerAddressSnapshotResponseFromJson(json);

  Map<String, dynamic> toJson() =>
      _$CustomerAddressSnapshotResponseToJson(this);

  CustomerAddressSnapshot toCustomerAddressSnapshot() {
    return CustomerAddressSnapshot(
      label: label,
      fullAddress: fullAddress,
      latitude: latitude,
      longitude: longitude,
    );
  }
}

@JsonSerializable()
class OrderItemInfoResponse {
  final String id;

  @JsonKey(name: 'product_image_url_snapshot')
  final String? productImageUrlSnapshot;

  @JsonKey(name: 'product_name_snapshot')
  final String productNameSnapshot;

  @JsonKey(name: 'product_variant_name_snapshot')
  final String? productVariantNameSnapshot;

  @JsonKey(name: 'selling_price_snapshot', fromJson: toDouble)
  final double sellingPriceSnapshot;

  final int quantity;

  const OrderItemInfoResponse({
    required this.id,
    required this.productImageUrlSnapshot,
    required this.productNameSnapshot,
    required this.productVariantNameSnapshot,
    required this.sellingPriceSnapshot,
    required this.quantity,
  });

  factory OrderItemInfoResponse.fromJson(Map<String, dynamic> json) =>
      _$OrderItemInfoResponseFromJson(json);

  Map<String, dynamic> toJson() => _$OrderItemInfoResponseToJson(this);

  OrderItemInfo toOrderItemInfo() {
    return OrderItemInfo(
      id: id,
      productImageUrlSnapshot: productImageUrlSnapshot,
      productNameSnapshot: productNameSnapshot,
      productVariantNameSnapshot: productVariantNameSnapshot,
      sellingPriceSnapshot: sellingPriceSnapshot,
      quantity: quantity,
    );
  }
}

@JsonSerializable()
class ProductReviewItemResponse {
  @JsonKey(name: 'product_variant_id')
  final String productVariantId;

  @JsonKey(name: 'product_image_url_snapshot')
  final String? productImageUrlSnapshot;

  @JsonKey(name: 'product_name_snapshot')
  final String productNameSnapshot;

  @JsonKey(name: 'product_variant_name_snapshot')
  final String? productVariantNameSnapshot;

  const ProductReviewItemResponse({
    required this.productVariantId,
    this.productImageUrlSnapshot,
    required this.productNameSnapshot,
    this.productVariantNameSnapshot,
  });

  factory ProductReviewItemResponse.fromJson(Map<String, dynamic> json) =>
      _$ProductReviewItemResponseFromJson(json);

  Map<String, dynamic> toJson() => _$ProductReviewItemResponseToJson(this);

  ProductReviewItem toProductReviewItem() {
    return ProductReviewItem(
      id: productVariantId,
      image: productImageUrlSnapshot,
      name: productNameSnapshot,
      variantName: productVariantNameSnapshot,
    );
  }
}

@JsonSerializable()
class ProductReviewRequest {
  @JsonKey(name: 'customer_id')
  final String customerId;

  @JsonKey(name: 'product_variant_id')
  final String productVariantId;

  final int rating;

  final String? comment;

  const ProductReviewRequest({
    required this.customerId,
    required this.productVariantId,
    required this.rating,
    this.comment,
  });

  factory ProductReviewRequest.fromJson(Map<String, dynamic> json) =>
      _$ProductReviewRequestFromJson(json);

  Map<String, dynamic> toJson() => _$ProductReviewRequestToJson(this);
}
