"use server";

import { auth } from "@/auth";
import { db } from "@/lib/db";
import { createPoSchema } from "@/lib/validations/po";
import { parsePoTerms } from "@/lib/terms";
import { notify } from "@/lib/notifier";
import { revalidatePath } from "next/cache";

function parseLineItems(formData: FormData) {
  const items = [];
  let i = 0;
  while (formData.has(`lineItems[${i}].name`)) {
    items.push({
      name: formData.get(`lineItems[${i}].name`) as string,
      description: (formData.get(`lineItems[${i}].description`) as string) || undefined,
      quantity: Number(formData.get(`lineItems[${i}].quantity`)),
      unit: formData.get(`lineItems[${i}].unit`) as string,
      size: (formData.get(`lineItems[${i}].size`) as string) || undefined,
      unitPrice: Number(formData.get(`lineItems[${i}].unitPrice`)),
      gstRate: Number(formData.get(`lineItems[${i}].gstRate`) ?? 0.18),
      accountId: (formData.get(`lineItems[${i}].accountId`) as string) || undefined,
    });
    i++;
  }
  return items;
}

export async function updatePo(
  poId: string,
  formData: FormData
): Promise<{ id: string } | { error: string }> {
  const session = await auth();
  if (!session?.user) return { error: "Unauthorized" };

  const po = await db.purchaseOrder.findUnique({ where: { id: poId } });
  if (!po) return { error: "PO not found" };
  if (!["DRAFT", "EDITS_REQUESTED"].includes(po.status)) {
    return { error: "This PO cannot be edited in its current state." };
  }
  if (po.submitterId !== session.user.id && session.user.role !== "SUPERUSER") {
    return { error: "You can only edit your own purchase orders." };
  }

  const intent = formData.get("intent") as "save" | "submit" | "resubmit";

  const parsed = createPoSchema.safeParse({
    title: formData.get("title"),
    vesselId: formData.get("vesselId"),
    accountId: formData.get("accountId"),
    companyId: (formData.get("companyId") as string) || undefined,
    poDate: formData.get("poDate") || undefined,
    projectCode: formData.get("projectCode") || undefined,
    dateRequired: formData.get("dateRequired") || undefined,
    vendorId: formData.get("vendorId") || undefined,
    piQuotationNo: formData.get("piQuotationNo") || undefined,
    piQuotationDate: formData.get("piQuotationDate") || undefined,
    requisitionNo: formData.get("requisitionNo") || undefined,
    requisitionDate: formData.get("requisitionDate") || undefined,
    placeOfDelivery: formData.get("placeOfDelivery") || undefined,
    tcDelivery: formData.get("tcDelivery") || undefined,
    tcDispatch: formData.get("tcDispatch") || undefined,
    tcInspection: formData.get("tcInspection") || undefined,
    tcTransitInsurance: formData.get("tcTransitInsurance") || undefined,
    tcPaymentTerms: formData.get("tcPaymentTerms") || undefined,
    tcOthers: formData.get("tcOthers") || undefined,
    lineItems: parseLineItems(formData),
  });

  if (!parsed.success) {
    return { error: parsed.error.errors[0]?.message ?? "Validation failed" };
  }

  const data = parsed.data;
  // Dynamic T&C rows (issue #11) — JSON snapshot superseding the tc* columns.
  let termsRaw: unknown = [];
  try { termsRaw = JSON.parse((formData.get("termsJson") as string) || "[]"); } catch { /* ignore */ }
  const terms = parsePoTerms(termsRaw);

  const total = data.lineItems.reduce(
    (sum, item) => sum + item.quantity * item.unitPrice * (1 + item.gstRate),
    0
  );

  const isSubmit   = intent === "submit"   && po.status === "DRAFT";
  const isResubmit = intent === "resubmit" && po.status === "EDITS_REQUESTED";
  const shouldSubmit = isSubmit || isResubmit;

  // Before mutating, snapshot the current PO state so the manager can see
  // exactly what the submitter changed when they resubmit after edits requested.
  let resubmitSnapshot: {
    lineItems: Array<{
      name: string; description: string | null; quantity: number;
      unit: string; size: string | null; unitPrice: number; gstRate: number;
    }>;
    fields: {
      title: string;
      vessel: string | null; vesselId: string;
      account: string; accountId: string;
      vendor: string | null; vendorId: string | null;
      poDate: string | null; projectCode: string | null; dateRequired: string | null; placeOfDelivery: string | null;
    };
  } | null = null;

  if (isResubmit) {
    const currentPo = await db.purchaseOrder.findUnique({
      where: { id: poId },
      include: {
        lineItems: { orderBy: { sortOrder: "asc" } },
        vessel: true,
        account: true,
        vendor: true,
      },
    });
    if (currentPo) {
      resubmitSnapshot = {
        lineItems: currentPo.lineItems.map((li) => ({
          name: li.name,
          description: li.description,
          quantity: Number(li.quantity),
          unit: li.unit,
          size: li.size,
          unitPrice: Number(li.unitPrice),
          gstRate: Number(li.gstRate),
        })),
        fields: {
          title: currentPo.title,
          vessel: currentPo.vessel?.name ?? null,
          vesselId: currentPo.vesselId,
          account: `${currentPo.account.name} (${currentPo.account.code})`,
          accountId: currentPo.accountId,
          vendor: currentPo.vendor?.name ?? null,
          vendorId: currentPo.vendorId,
          poDate: currentPo.poDate?.toISOString() ?? null,
          projectCode: currentPo.projectCode,
          dateRequired: currentPo.dateRequired?.toISOString() ?? null,
          placeOfDelivery: currentPo.placeOfDelivery,
        },
      };
    }
  }

  await db.purchaseOrder.update({
    where: { id: poId },
    data: {
      title: data.title,
      vesselId: data.vesselId,
      accountId: data.accountId,
      companyId: data.companyId ?? null,
      vendorId: data.vendorId ?? null,
      poDate: data.poDate ? new Date(data.poDate) : null,
      projectCode: data.projectCode ?? null,
      dateRequired: data.dateRequired ? new Date(data.dateRequired) : null,
      piQuotationNo: data.piQuotationNo ?? null,
      piQuotationDate: data.piQuotationDate ? new Date(data.piQuotationDate) : null,
      requisitionNo: data.requisitionNo ?? null,
      requisitionDate: data.requisitionDate ? new Date(data.requisitionDate) : null,
      placeOfDelivery: data.placeOfDelivery ?? null,
      tcDelivery: data.tcDelivery ?? null,
      tcDispatch: data.tcDispatch ?? null,
      tcInspection: data.tcInspection ?? null,
      tcTransitInsurance: data.tcTransitInsurance ?? null,
      tcPaymentTerms: data.tcPaymentTerms ?? null,
      tcOthers: data.tcOthers ?? null,
      terms,
      totalAmount: total,
      status: shouldSubmit ? "MGR_REVIEW" : "DRAFT",
      submittedAt: shouldSubmit ? new Date() : po.submittedAt,
      lineItems: {
        deleteMany: {},
        create: data.lineItems.map((item, idx) => ({
          name: item.name,
          description: item.description ?? null,
          quantity: item.quantity,
          unit: item.unit,
          size: item.size ?? null,
          unitPrice: item.unitPrice,
          totalPrice: item.quantity * item.unitPrice,
          gstRate: item.gstRate,
          sortOrder: idx,
          accountId: (item as { accountId?: string }).accountId ?? null,
        })),
      },
      actions: {
        create: shouldSubmit
          ? {
              actionType: "SUBMITTED",
              actorId: session.user.id,
              ...(isResubmit && resubmitSnapshot ? { metadata: { editSnapshot: resubmitSnapshot } } : {}),
            }
          : undefined,
      },
    },
  });

  if (shouldSubmit) {
    const [fullPo, managers] = await Promise.all([
      db.purchaseOrder.findUnique({ where: { id: poId }, include: { submitter: true } }),
      db.user.findMany({ where: { role: "MANAGER", isActive: true } }),
    ]);
    if (fullPo) {
      await notify({ event: "PO_SUBMITTED", po: fullPo, recipients: managers });
    }
  }

  revalidatePath(`/po/${poId}`);
  revalidatePath("/dashboard");
  return { id: poId };
}
