import type { LotDetail, LotListItem, LotTransformationTrace } from "@/types/lot";

type DecimalLike = { toNumber(): number };

type LotListSerializable = {
  id: bigint;
  lotCode: string;
  originalQty: DecimalLike;
  availableQty: DecimalLike;
  unitCost: DecimalLike;
  unit: { code: string };
  receivedAt: Date;
  status: string;
  purchase: {
    id: bigint;
    agent: {
      id: bigint;
      name: string;
    } | null;
  } | null;
  grade: { name: string } | null;
  warehouse: { name: string };
  warehouseLocation: { name: string } | null;
};

type LotDetailSerializable = {
  id: bigint;
  lotCode: string;
  sourceType: string;
  originalQty: DecimalLike;
  availableQty: DecimalLike;
  reservedQty: DecimalLike;
  damagedQty: DecimalLike;
  shrinkageQty: DecimalLike;
  unit: { code: string };
  unitCost: DecimalLike;
  receivedAt: Date;
  status: string;
  qrCodeValue: string | null;
  barcodeValue: string | null;
  supplier?: {
    id: bigint;
    name: string;
  } | null;
  grade: { id: bigint; name: string } | null;
  warehouse: { id: bigint; name: string };
  warehouseLocation: { id: bigint; name: string } | null;
  purchase: {
    id: bigint;
    purchaseNo: string;
    purchaseDate: Date;
    agent: { id: bigint; name: string } | null;
    buyoutSourceAgent?: { id: bigint; name: string } | null;
  } | null;
  purchaseLine?: {
    unitPrice: DecimalLike;
    buyoutMalUnitPriceSnapshot: DecimalLike | null;
    buyoutAgentSharePercent: DecimalLike | null;
    buyoutProfitAmount: DecimalLike | null;
    buyoutAgentCommission: DecimalLike | null;
  } | null;
  receipt: { id: bigint; receiptNo: string; receiptDate: Date } | null;
  parentLot: { id: bigint; lotCode: string } | null;
  childLots: Array<{
    id: bigint;
    lotCode: string;
    status: string;
    availableQty: DecimalLike;
    sourceType: string;
  }>;
  transformationOutputs: Array<{
    transformation: TransformationSerializable;
  }>;
  transformationInputs: Array<{
    transformation: TransformationSerializable;
  }>;
  consignmentLines: Array<{
    id: bigint;
    qtyConsigned: DecimalLike;
    qtySold: DecimalLike;
    qtyReturned: DecimalLike;
    qtyShrinkage: DecimalLike;
    sellingPrice: DecimalLike | null;
    salesCommission: DecimalLike;
    agentCommission: DecimalLike;
    closeDate: Date | null;
    status: string;
    consignment: {
      id: bigint;
      consignmentNo: string;
      consignmentDate: Date;
      status: string;
      sales: { name: string };
      buyer: { name: string };
    };
  }>;
};

type TransformationSerializable = {
  id: bigint;
  transformationNo: string;
  transformationType: string;
  transformationDate: Date;
  status: string;
  notes: string | null;
  inputs: Array<{
    id: bigint;
    qtyUsed: DecimalLike;
    unitCostSnapshot: DecimalLike;
    sourceLot: {
      id: bigint;
      lotCode: string;
      grade: { name: string } | null;
    };
  }>;
  outputs: Array<{
    id: bigint;
    qtyProduced: DecimalLike;
    resultLot: {
      id: bigint;
      lotCode: string;
      availableQty: DecimalLike;
      unitCost: DecimalLike;
      status: string;
      grade: { name: string } | null;
    };
  }>;
};

const DEFAULT_PARTNER_NAME = "Pembelian bebas";

function getPartnerName(
  purchase: LotListSerializable["purchase"] | LotDetailSerializable["purchase"] | null
) {
  if (!purchase) return DEFAULT_PARTNER_NAME;
  return purchase.agent?.name ?? DEFAULT_PARTNER_NAME;
}

function getAgingDays(receivedAt: Date) {
  const diffMs = Date.now() - receivedAt.getTime();
  return Math.max(0, Math.floor(diffMs / (1000 * 60 * 60 * 24)));
}

export function serializeLotListItem(lot: LotListSerializable): LotListItem {
  return {
    id: lot.id.toString(),
    lot_code: lot.lotCode,
    supplier: getPartnerName(lot.purchase),
    grade: lot.grade?.name ?? "-",
    original_qty: lot.originalQty.toNumber(),
    available_qty: lot.availableQty.toNumber(),
    unit_cost: lot.unitCost.toNumber(),
    unit_code: lot.unit.code,
    warehouse: lot.warehouse.name,
    location: lot.warehouseLocation?.name ?? null,
    aging_days: getAgingDays(lot.receivedAt),
    status: lot.status
  };
}

function serializeTransformationTrace(
  transformation: TransformationSerializable
): LotTransformationTrace {
  return {
    id: transformation.id.toString(),
    transformation_no: transformation.transformationNo,
    transformation_type: transformation.transformationType,
    transformation_date: transformation.transformationDate.toISOString(),
    status: transformation.status,
    notes: transformation.notes,
    inputs: transformation.inputs.map((input) => {
      return {
        id: input.id.toString(),
        lot_id: input.sourceLot.id.toString(),
        lot_code: input.sourceLot.lotCode,
        grade: input.sourceLot.grade?.name ?? "-",
        qty_used: input.qtyUsed.toNumber(),
        unit_cost_snapshot: input.unitCostSnapshot.toNumber()
      };
    }),
    outputs: transformation.outputs.map((output) => {
      return {
        id: output.id.toString(),
        lot_id: output.resultLot.id.toString(),
        lot_code: output.resultLot.lotCode,
        grade: output.resultLot.grade?.name ?? "-",
        qty_produced: output.qtyProduced.toNumber(),
        available_qty: output.resultLot.availableQty.toNumber(),
        unit_cost: output.resultLot.unitCost.toNumber(),
        status: output.resultLot.status
      };
    })
  };
}

export function serializeLotDetail(lot: LotDetailSerializable): LotDetail {
  const labels: LotDetail["labels"] = [];
  if (lot.qrCodeValue) labels.push({ type: "QR", value: lot.qrCodeValue });
  if (lot.barcodeValue) labels.push({ type: "BARCODE", value: lot.barcodeValue });

  return {
    id: lot.id.toString(),
    lot_code: lot.lotCode,
    source_type: lot.sourceType,
    supplier: lot.supplier
      ? {
          id: lot.supplier.id.toString(),
          name: lot.supplier.name
        }
      : lot.purchase
        ? {
            id: "",
            name: getPartnerName(lot.purchase)
          }
        : null,
    grade: lot.grade
      ? {
          id: lot.grade.id.toString(),
          name: lot.grade.name
        }
      : null,
    original_qty: lot.originalQty.toNumber(),
    available_qty: lot.availableQty.toNumber(),
    reserved_qty: lot.reservedQty.toNumber(),
    damaged_qty: lot.damagedQty.toNumber(),
    shrinkage_qty: lot.shrinkageQty.toNumber(),
    unit_code: lot.unit.code,
    unit_cost: lot.unitCost.toNumber(),
    warehouse: {
      id: lot.warehouse.id.toString(),
      name: lot.warehouse.name
    },
    location: lot.warehouseLocation
      ? {
          id: lot.warehouseLocation.id.toString(),
          name: lot.warehouseLocation.name
        }
      : null,
    status: lot.status,
    parent_lot: lot.parentLot
      ? {
          id: lot.parentLot.id.toString(),
          lot_code: lot.parentLot.lotCode
        }
      : null,
    buyout_info:
      lot.sourceType === "OFFICE_BUYOUT"
        ? {
            source_agent_name: lot.purchase?.buyoutSourceAgent?.name ?? lot.purchase?.agent?.name ?? null,
            mal_unit_price_snapshot: lot.purchaseLine?.buyoutMalUnitPriceSnapshot?.toNumber() ?? 0,
            agent_share_percent: lot.purchaseLine?.buyoutAgentSharePercent?.toNumber() ?? 0,
            profit_amount: lot.purchaseLine?.buyoutProfitAmount?.toNumber() ?? 0,
            agent_commission: lot.purchaseLine?.buyoutAgentCommission?.toNumber() ?? 0,
            buyout_unit_price: lot.purchaseLine?.unitPrice.toNumber() ?? lot.unitCost.toNumber()
          }
        : null,
    child_lots: lot.childLots.map((child) => ({
      id: child.id.toString(),
      lot_code: child.lotCode,
      status: child.status,
      available_qty: child.availableQty.toNumber(),
      source_type: child.sourceType
    })),
    produced_by_transformations: lot.transformationOutputs.map((row) =>
      serializeTransformationTrace(row.transformation)
    ),
    used_in_transformations: lot.transformationInputs.map((row) =>
      serializeTransformationTrace(row.transformation)
    ),
    consignments: lot.consignmentLines.map((line) => ({
      id: line.consignment.id.toString(),
      consignment_no: line.consignment.consignmentNo,
      consignment_date: line.consignment.consignmentDate.toISOString(),
      sales_name: line.consignment.sales.name,
      buyer_name: line.consignment.buyer.name,
      status: line.status,
      qty_consigned: line.qtyConsigned.toNumber(),
      qty_sold: line.qtySold.toNumber(),
      qty_returned: line.qtyReturned.toNumber(),
      qty_shrinkage: line.qtyShrinkage.toNumber(),
      selling_price: line.sellingPrice?.toNumber() ?? null,
      sales_commission: line.salesCommission.toNumber(),
      agent_commission: line.agentCommission.toNumber(),
      close_date: line.closeDate?.toISOString() ?? null
    })),
    labels,
    purchase: lot.purchase
      ? {
          id: lot.purchase.id.toString(),
          purchase_no: lot.purchase.purchaseNo,
          purchase_date: lot.purchase.purchaseDate.toISOString()
        }
      : null,
    receipt: lot.receipt
      ? {
          id: lot.receipt.id.toString(),
          receipt_no: lot.receipt.receiptNo,
          receipt_date: lot.receipt.receiptDate.toISOString()
        }
      : null,
    received_at: lot.receivedAt.toISOString()
  };
}
