import { Prisma } from "../generated/prisma/client.js";

export interface SaleItemCalcInput {
  saleUnit: "KG" | "BOX" | "BAG" | "THAAR" | "PIECES";
  quantity?: Prisma.Decimal | number | string;
  bags?: Prisma.Decimal | number | string;
  sellingRate: Prisma.Decimal | number | string;
  vegetableName?: string;
  lotNo?: string;
  purchase: {
    remainingQuantity: Prisma.Decimal;
    remainingBags: Prisma.Decimal;
    weightPerBag: Prisma.Decimal | null;
    costPerUnit: Prisma.Decimal;
    rateType?: string;
    isFlexible?: boolean;
    vegetableName?: string;
    lotNo?: string;
  };
}

function getItemPrefix(input: SaleItemCalcInput): string {
  const vegName = input.vegetableName || input.purchase.vegetableName;
  const lot = input.lotNo || input.purchase.lotNo;
  if (vegName && lot) {
    return `[${vegName} - Lot: ${lot}] `;
  }
  if (vegName) {
    return `[${vegName}] `;
  }
  if (lot) {
    return `[Lot: ${lot}] `;
  }
  return "";
}

export function calculateSaleItem(input: SaleItemCalcInput) {
  const prefix = getItemPrefix(input);
  const sellingRate = new Prisma.Decimal(input.sellingRate);
  if (sellingRate.lt(0)) {
    throw new Error(`${prefix}Selling rate cannot be negative`);
  }

  let kgQty: Prisma.Decimal;
  let boxQty: Prisma.Decimal | null = null;
  let total: Prisma.Decimal;

  let explicitKg = false;
  let explicitBags = false;

  if (input.saleUnit === "PIECES") {
    if (input.quantity === undefined && input.bags === undefined) {
      throw new Error(`${prefix}Quantity (pieces) is required for PIECES sale`);
    }

    const pieceRaw = input.quantity !== undefined && input.quantity !== null && input.quantity !== ""
      ? input.quantity
      : input.bags;

    kgQty = new Prisma.Decimal(pieceRaw!);
    explicitKg = true;
    if (kgQty.lte(0)) {
      throw new Error(`${prefix}Piece quantity must be greater than 0`);
    }

    total = kgQty.mul(sellingRate).toDecimalPlaces(2, Prisma.Decimal.ROUND_HALF_UP);

  } else if (input.saleUnit === "THAAR") {
    if (input.quantity === undefined && input.bags === undefined) {
      throw new Error(`${prefix}Thaar count is required for THAAR sale`);
    }

    const thaarRaw = (input.quantity !== undefined && input.quantity !== null && input.quantity !== "")
      ? input.quantity
      : input.bags;

    if (thaarRaw === undefined || thaarRaw === null || thaarRaw === "") {
      throw new Error(`${prefix}Thaar count is required for THAAR sale`);
    }

    kgQty = new Prisma.Decimal(thaarRaw);
    explicitKg = true;
    if (kgQty.lte(0)) {
      throw new Error(`${prefix}Thaar count must be greater than 0`);
    }

    total = kgQty.mul(sellingRate).toDecimalPlaces(2, Prisma.Decimal.ROUND_HALF_UP);

  } else if (input.saleUnit === "KG") {
    if (input.quantity === undefined) {
      throw new Error(`${prefix}Quantity is required for KG sale`);
    }

    kgQty = new Prisma.Decimal(input.quantity);
    explicitKg = true;
    if (kgQty.lte(0)) {
      throw new Error(`${prefix}Quantity must be greater than 0`);
    }

    if (input.bags !== undefined && input.bags !== null && input.bags !== "") {
      boxQty = new Prisma.Decimal(input.bags);
      explicitBags = true;
      if (boxQty.lte(0)) {
        throw new Error(`${prefix}Bag count must be greater than 0`);
      }
    } else if (input.purchase.weightPerBag) {
      // Auto-calculate bags
      if (kgQty.eq(input.purchase.remainingQuantity)) {
        boxQty = input.purchase.remainingBags;
      } else {
        boxQty = kgQty.div(input.purchase.weightPerBag).toDecimalPlaces(3, Prisma.Decimal.ROUND_HALF_UP);
      }
    }

    total = kgQty.mul(sellingRate).toDecimalPlaces(2, Prisma.Decimal.ROUND_HALF_UP);

  } else {
    // BOX / BAG sale
    if (!input.purchase.isFlexible && !input.purchase.weightPerBag && input.purchase.rateType !== "UNIT") {
      throw new Error(`${prefix}This lot was purchased loose in KG and cannot be sold by box/bag`);
    }

    if (input.bags === undefined) {
      throw new Error(`${prefix}Bags is required for BOX/BAG sale`);
    }

    boxQty = new Prisma.Decimal(input.bags);
    explicitBags = true;
    if (boxQty.lte(0)) {
      throw new Error(`${prefix}Bags must be greater than 0`);
    }

    if (input.quantity !== undefined && input.quantity !== null && input.quantity !== "") {
      kgQty = new Prisma.Decimal(input.quantity);
      explicitKg = true;
      if (kgQty.lte(0)) {
        throw new Error(`${prefix}Quantity must be greater than 0`);
      }
    } else {
      if (!input.purchase.isFlexible && input.purchase.rateType !== "UNIT") {
        throw new Error(`${prefix}This item is priced by weight. It cannot be sold by Box/Bag alone.`);
      }
      // Auto-calculate KG
      if (boxQty.eq(input.purchase.remainingBags)) {
        kgQty = input.purchase.remainingQuantity;
      } else {
        kgQty = input.purchase.weightPerBag
          ? boxQty.mul(input.purchase.weightPerBag).toDecimalPlaces(3, Prisma.Decimal.ROUND_HALF_UP)
          : (input.purchase.remainingQuantity.isZero() ? new Prisma.Decimal(0) : boxQty);
      }
    }

    total = boxQty.mul(sellingRate).toDecimalPlaces(2, Prisma.Decimal.ROUND_HALF_UP);
  }

  // --- Validation ---
  if (!input.purchase.isFlexible) {
    if ((input.purchase.remainingQuantity.gt(0) || explicitKg) && kgQty.gt(input.purchase.remainingQuantity)) {
      throw new Error(`${prefix}Sale quantity cannot exceed available stock quantity (${input.purchase.remainingQuantity.toFixed(3)} kg remaining).`);
    }
    if (boxQty !== null && boxQty.gt(input.purchase.remainingBags)) {
      throw new Error(`${prefix}Sale bag count cannot exceed available bag count (${input.purchase.remainingBags.toFixed(3)} bags remaining).`);
    }

    // --- Strong validation: Both stocks must reach 0 together ---
    if (explicitKg && explicitBags && input.purchase.remainingBags.gt(0) && input.purchase.remainingQuantity.gt(0)) {
      const remainingKg = input.purchase.remainingQuantity.sub(kgQty);
      const remainingBags = input.purchase.remainingBags.sub(boxQty!);

      if (remainingKg.lte(0) && remainingBags.gt(0)) {
        throw new Error(`${prefix}Invalid stock combination: KG is completely sold, but bags remain. Both must reach zero together.`);
      }
      if (remainingBags.lte(0) && remainingKg.gt(0)) {
        throw new Error(`${prefix}Invalid stock combination: Bags are completely sold, but KG remains. Both must reach zero together.`);
      }
    }
  }

  return {
    quantity: kgQty,
    bags: boxQty,
    costPerUnit: input.purchase.costPerUnit,
    sellingRate,
    total,
  };
}
