import type {
  ConsignmentCandidateLot,
  ConsignmentDetail,
  ConsignmentListItem
} from "@/types/consignment";

type DecimalLike = { toNumber(): number };

type SerializableCandidateLot = {
  id: bigint;
  lotCode: string;
  availableQty: DecimalLike;
  unitCost: DecimalLike;
  purchaseLine: {
    malUnitPrice: DecimalLike | null;
  } | null;
  grade: { name: string } | null;
  unit: { code: string };
  warehouse: { name: string };
  warehouseLocation: { name: string } | null;
};

type SerializableConsignmentList = {
  id: bigint;
  consignmentNo: string;
  consignmentDate: Date;
  status: string;
  sales: {
    id: bigint;
    code: string;
    name: string;
  };
  buyer: {
    id: bigint;
    code: string;
    name: string;
  };
  lines: Array<{
    status: string;
    qtyConsigned: DecimalLike;
    qtySold: DecimalLike;
    qtyReturned: DecimalLike;
    qtyShrinkage: DecimalLike;
  }>;
};

type SerializableConsignmentDetail = {
  id: bigint;
  consignmentNo: string;
  consignmentDate: Date;
  status: string;
  notes: string | null;
  createdAt: Date;
  sales: {
    id: bigint;
    code: string;
    name: string;
  };
  buyer: {
    id: bigint;
    code: string;
    name: string;
  };
  lines: Array<{
    id: bigint;
    qtyConsigned: DecimalLike;
    availableQtySnapshot: DecimalLike;
    malUnitPriceSnapshot: DecimalLike | null;
    agentNameSnapshot: string | null;
    agentSharePercent: DecimalLike | null;
    status: string;
    notes: string | null;
    closeDate: Date | null;
    sellingPrice: DecimalLike | null;
    qtySold: DecimalLike;
    qtyReturned: DecimalLike;
    qtyShrinkage: DecimalLike;
    salesCommission: DecimalLike;
    agentCommission: DecimalLike;
    lot: {
      id: bigint;
      lotCode: string;
      availableQty: DecimalLike;
      unitCost: DecimalLike;
      purchase: {
        agent: { name: string } | null;
        profitShareScheme: { shareAgent: DecimalLike } | null;
      } | null;
      grade: { name: string } | null;
      unit: { code: string };
      warehouse: { name: string };
      warehouseLocation: { name: string } | null;
    };
  }>;
};

function toDateOnly(value: Date | null) {
  return value ? value.toISOString().slice(0, 10) : null;
}

export function serializeConsignmentCandidateLot(
  lot: SerializableCandidateLot
): ConsignmentCandidateLot {
  return {
    lot_id: lot.id.toString(),
    lot_code: lot.lotCode,
    grade: lot.grade?.name ?? "-",
    unit_code: lot.unit.code,
    warehouse: lot.warehouse.name,
    location: lot.warehouseLocation?.name ?? null,
    available_qty: lot.availableQty.toNumber(),
    unit_cost: lot.unitCost.toNumber(),
    mal_unit_price: lot.purchaseLine?.malUnitPrice?.toNumber() ?? null
  };
}

export function serializeConsignmentListItem(
  consignment: SerializableConsignmentList
): ConsignmentListItem {
  return {
    id: consignment.id.toString(),
    consignment_no: consignment.consignmentNo,
    consignment_date: consignment.consignmentDate.toISOString().slice(0, 10),
    sales: {
      id: consignment.sales.id.toString(),
      code: consignment.sales.code,
      name: consignment.sales.name
    },
    buyer: {
      id: consignment.buyer.id.toString(),
      code: consignment.buyer.code,
      name: consignment.buyer.name
    },
    status: consignment.status,
    item_count: consignment.lines.length,
    open_item_count: consignment.lines.filter((line) => line.status !== "CLOSED").length,
    total_qty_consigned: consignment.lines.reduce((sum, line) => sum + line.qtyConsigned.toNumber(), 0),
    total_qty_sold: consignment.lines.reduce((sum, line) => sum + line.qtySold.toNumber(), 0),
    total_qty_returned: consignment.lines.reduce((sum, line) => sum + line.qtyReturned.toNumber(), 0),
    total_qty_shrinkage: consignment.lines.reduce((sum, line) => sum + line.qtyShrinkage.toNumber(), 0)
  };
}

export function serializeConsignmentDetail(
  consignment: SerializableConsignmentDetail
): ConsignmentDetail {
  return {
    id: consignment.id.toString(),
    consignment_no: consignment.consignmentNo,
    consignment_date: consignment.consignmentDate.toISOString().slice(0, 10),
    sales: {
      id: consignment.sales.id.toString(),
      code: consignment.sales.code,
      name: consignment.sales.name
    },
    buyer: {
      id: consignment.buyer.id.toString(),
      code: consignment.buyer.code,
      name: consignment.buyer.name
    },
    status: consignment.status,
    notes: consignment.notes,
    created_at: consignment.createdAt.toISOString(),
    lines: consignment.lines.map((line) => {
      return {
        id: line.id.toString(),
        lot_id: line.lot.id.toString(),
        lot_code: line.lot.lotCode,
        grade: line.lot.grade?.name ?? "-",
        unit_code: line.lot.unit.code,
        warehouse: line.lot.warehouse.name,
        location: line.lot.warehouseLocation?.name ?? null,
        available_qty_snapshot: line.availableQtySnapshot.toNumber(),
        current_available_qty: line.lot.availableQty.toNumber(),
        qty_consigned: line.qtyConsigned.toNumber(),
        mal_unit_price_snapshot: line.malUnitPriceSnapshot?.toNumber() ?? null,
        agent_name_snapshot: line.agentNameSnapshot ?? line.lot.purchase?.agent?.name ?? null,
        agent_share_percent:
          line.agentSharePercent?.toNumber() ??
          line.lot.purchase?.profitShareScheme?.shareAgent.toNumber() ??
          null,
        unit_cost: line.lot.unitCost.toNumber(),
        status: line.status,
        notes: line.notes,
        close_date: toDateOnly(line.closeDate),
        selling_price: line.sellingPrice?.toNumber() ?? null,
        qty_sold: line.qtySold.toNumber(),
        qty_returned: line.qtyReturned.toNumber(),
        qty_shrinkage: line.qtyShrinkage.toNumber(),
        sales_commission: line.salesCommission.toNumber(),
        agent_commission: line.agentCommission.toNumber()
      };
    })
  };
}
