import { Prisma } from "@prisma/client";

export type LotAllocationSnapshot = {
  id: bigint | null;
  purchaseId: bigint;
  purchaseLineId: bigint | null;
  sourceType: string;
  sourceRefId: bigint | null;
  agentIdSnapshot: bigint | null;
  profitShareSchemeIdSnapshot: bigint | null;
  qtyAllocated: Prisma.Decimal;
  costTotalAllocated: Prisma.Decimal;
  unitCostSnapshot: Prisma.Decimal;
};

type FallbackLotSource = {
  id: bigint;
  purchaseId: bigint | null;
  purchaseLineId: bigint | null;
  unitCost: Prisma.Decimal;
  availableQty: Prisma.Decimal;
  purchase?: {
    id: bigint;
    agentId: bigint | null;
    profitShareSchemeId: bigint | null;
  } | null;
  purchaseAllocations?: LotAllocationSnapshot[];
};

export function roundQty(value: number) {
  return Number(value.toFixed(3));
}

export function roundAmount(value: number) {
  return Number(value.toFixed(2));
}

export function getEffectiveLotAllocations(lot: FallbackLotSource): LotAllocationSnapshot[] {
  if (lot.purchaseAllocations && lot.purchaseAllocations.length > 0) {
    return lot.purchaseAllocations;
  }

  if (!lot.purchaseId && !lot.purchase?.id) {
    return [];
  }

  const purchaseId = lot.purchase?.id ?? lot.purchaseId!;
  return [
    {
      id: null,
      purchaseId,
      purchaseLineId: lot.purchaseLineId,
      sourceType: "PURCHASE",
      sourceRefId: purchaseId,
      agentIdSnapshot: lot.purchase?.agentId ?? null,
      profitShareSchemeIdSnapshot: lot.purchase?.profitShareSchemeId ?? null,
      qtyAllocated: new Prisma.Decimal(lot.availableQty),
      costTotalAllocated: new Prisma.Decimal(
        roundAmount(lot.availableQty.toNumber() * lot.unitCost.toNumber())
      ),
      unitCostSnapshot: lot.unitCost
    }
  ];
}

export function buildAllocationShares(
  allocations: LotAllocationSnapshot[],
  sourceAvailableQty: number,
  affectedQty: number
) {
  return allocations
    .map((allocation) => {
      const allocationQty = allocation.qtyAllocated.toNumber();
      if (sourceAvailableQty <= 0 || allocationQty <= 0) {
        return null;
      }

      const ratio = allocationQty / sourceAvailableQty;
      const affectedAllocationQty = roundQty(affectedQty * ratio);
      const remainingQty = roundQty(Math.max(0, allocationQty - affectedAllocationQty));

      return {
        allocation,
        allocationQty,
        ratio,
        affectedAllocationQty,
        remainingQty
      };
    })
    .filter((item): item is NonNullable<typeof item> => item !== null && item.affectedAllocationQty > 0);
}
