import { NextResponse } from "next/server";
import { Prisma } from "@prisma/client";

import { recalculatePurchaseRealizationSummary } from "@/features/purchase-realization/lib/recalculate-purchase-realization-summary";
import { generateLotCode } from "@/features/receipts/lib/generate-lot-code";
import { createAuditTrailSafe } from "@/lib/audit-trail";
import { requireApiAccess } from "@/lib/authorization";
import { prisma } from "@/lib/prisma";

type RouteContext = { params: Promise<{ id: string }> };

type GenerateLotsTx = Prisma.TransactionClient & {
  lotPurchaseAllocation: typeof prisma.lotPurchaseAllocation;
  purchaseRealizationEntry: typeof prisma.purchaseRealizationEntry;
  purchaseRealizationSummary: typeof prisma.purchaseRealizationSummary;
};

const parseId = (id: string) => {
  try {
    return BigInt(id);
  } catch {
    return null;
  }
};

export async function POST(request: Request, context: RouteContext) {
  const auth = requireApiAccess(request);
  if (!auth.ok) return auth.response;

  const parsedId = parseId((await context.params).id);
  if (parsedId === null) {
    return NextResponse.json({ message: "Invalid id" }, { status: 400 });
  }

  const existingReceipt = await prisma.receipt.findUnique({
    where: { id: parsedId },
    include: {
      purchase: {
        include: {
          agent: { select: { id: true, name: true } },
          profitShareScheme: { select: { id: true, shareAgent: true } }
        }
      },
      lines: true,
      lots: true
    }
  });

  if (!existingReceipt) {
    return NextResponse.json({ message: "Receipt not found" }, { status: 404 });
  }

  if (existingReceipt.lots.length > 0) {
    return NextResponse.json(
      { message: "Lots already generated for this receipt" },
      { status: 409 }
    );
  }

  const acceptedLines = existingReceipt.lines.filter((line) => Number(line.qtyAccepted.toNumber()) > 0);
  if (acceptedLines.length === 0) {
    return NextResponse.json(
      { message: "Tidak ada baris receipt dengan qty accepted > 0." },
      { status: 400 }
    );
  }

  try {
    const generated = await prisma.$transaction(async (rawTx) => {
      const tx = rawTx as GenerateLotsTx;
      const sourceCode = existingReceipt.purchase.agent?.name || existingReceipt.purchase.purchaseNo;
      const baseLotCode = await generateLotCode(existingReceipt.receiptDate, sourceCode);
      const codeMatch = baseLotCode.match(/-(\d+)$/);
      if (!codeMatch) {
        throw new Error("Gagal generate kode lot");
      }
      const lotPrefix = baseLotCode.replace(/-\d+$/, "");
      let lotSuffix = Number(codeMatch[1] ?? "0") || 1;

      const existingLotCount = await tx.inventoryLot.count({
        where: { receiptId: existingReceipt.id }
      });
      if (existingLotCount > 0) {
        throw new Error("Lot untuk receipt ini sudah pernah dibuat");
      }

      const lots = [];
      for (const line of acceptedLines) {
        const availableQty = Number(line.qtyAccepted.toNumber());
        const lotCode = `${lotPrefix}-${String(lotSuffix).padStart(3, "0")}`;
        lotSuffix += 1;

        const lot = await tx.inventoryLot.create({
          data: {
            lotCode,
            sourceType: "RECEIPT",
            sourceRefId: line.id,
            purchaseId: existingReceipt.purchaseId,
            purchaseLineId: line.purchaseLineId,
            receiptId: existingReceipt.id,
            receiptLineId: line.id,
            gradeId: line.gradeId,
            warehouseId: line.warehouseId,
            warehouseLocationId: line.warehouseLocationId,
            originalQty: line.qtyAccepted,
            availableQty: line.qtyAccepted,
            unitId: line.unitId,
            unitCost: line.unitCost,
            receivedAt: existingReceipt.receiptDate,
            status: "ACTIVE",
            qrCodeValue: lotCode,
            barcodeValue: lotCode
          }
        });

        const costTotalAllocated = Number((availableQty * line.unitCost.toNumber()).toFixed(2));
        const allocation = await tx.lotPurchaseAllocation.create({
          data: {
            lotId: lot.id,
            purchaseId: existingReceipt.purchaseId,
            purchaseLineId: line.purchaseLineId,
            sourceType: "RECEIPT",
            sourceRefId: existingReceipt.id,
            agentIdSnapshot: existingReceipt.purchase.agentId,
            profitShareSchemeIdSnapshot: existingReceipt.purchase.profitShareSchemeId,
            qtyAllocated: new Prisma.Decimal(availableQty),
            costTotalAllocated: new Prisma.Decimal(costTotalAllocated),
            unitCostSnapshot: line.unitCost
          }
        });

        await tx.purchaseRealizationEntry.create({
          data: {
            purchaseId: existingReceipt.purchaseId,
            lotId: lot.id,
            allocationId: allocation.id,
            eventType: "OPENING_COST",
            referenceType: "RECEIPT",
            referenceId: existingReceipt.id,
            occurredAt: existingReceipt.receiptDate,
            qtyIn: new Prisma.Decimal(availableQty),
            qtyOut: new Prisma.Decimal(0),
            qtyShrinkage: new Prisma.Decimal(0),
            amountCost: new Prisma.Decimal(costTotalAllocated),
            amountRevenue: new Prisma.Decimal(0),
            amountExpense: new Prisma.Decimal(0),
            amountProfit: new Prisma.Decimal(0),
            agentSharePercentSnapshot: existingReceipt.purchase.profitShareScheme?.shareAgent ?? null,
            agentAmount: new Prisma.Decimal(0),
            notes: `Opening realization dari receipt line ${line.id.toString()}`
          }
        });

        lots.push(lot);
      }

      await tx.receipt.update({
        where: { id: existingReceipt.id },
        data: { status: "FINALIZED" }
      });

      await tx.purchase.update({
        where: { id: existingReceipt.purchaseId },
        data: { status: "SUBMITTED" }
      });

      await recalculatePurchaseRealizationSummary(
        tx,
        existingReceipt.purchaseId,
        existingReceipt.purchase.profitShareScheme?.shareAgent.toNumber() ?? null
      );

      return lots;
    });

    await createAuditTrailSafe({
      userId: auth.user.id,
      action: "LOTS_GENERATED",
      entityType: "RECEIPT",
      entityId: existingReceipt.id,
      method: request.method,
      pathname: new URL(request.url).pathname,
      statusCode: 200,
      summary: `${generated.length} lot dibuat dari receipt ${existingReceipt.receiptNo}`,
      metadata: {
        receipt_no: existingReceipt.receiptNo,
        purchase_no: existingReceipt.purchase.purchaseNo,
        lot_codes: generated.map((lot) => lot.lotCode)
      }
    });

    return NextResponse.json({
      receipt_id: existingReceipt.id.toString(),
      lots: generated.map((lot) => ({
        id: lot.id.toString(),
        lot_code: lot.lotCode,
        qr_code_value: lot.qrCodeValue
      }))
    });
  } catch (error) {
    if (error instanceof Prisma.PrismaClientKnownRequestError && error.code === "P2002") {
      return NextResponse.json(
        { message: "Kode lot duplikat saat membuat lot. Coba lagi." },
        { status: 409 }
      );
    }
    if (error instanceof Error) {
      return NextResponse.json({ message: error.message }, { status: 400 });
    }
    throw error;
  }
}
