"use server";

import { auth } from "@/auth";
import { db } from "@/lib/db";
import { canPerformAction } from "@/lib/po-state-machine";
import { approvePoSchema } from "@/lib/validations/po";
import { syncProductCatalog } from "@/lib/product-catalog";
import { notify } from "@/lib/notifier";
import { revalidatePath } from "next/cache";

type ActionResult = { ok: true } | { error: string };

export async function approvePo({
  poId,
  note,
  withNote = false,
  suggestedAdvancePayment,
}: {
  poId: string;
  note?: string;
  withNote?: boolean;
  // Absolute advance the Manager wants paid first (issue #92). Whole amount,
  // resolved from the approval slider client-side. Omitted ⇒ full payment.
  suggestedAdvancePayment?: number;
}): Promise<ActionResult> {
  const session = await auth();
  if (!session?.user) return { error: "Unauthorized" };

  const parsed = approvePoSchema.safeParse({ note, suggestedAdvancePayment });
  if (!parsed.success) return { error: parsed.error.errors[0]?.message ?? "Validation failed" };

  const po = await db.purchaseOrder.findUnique({
    where: { id: poId },
    include: { submitter: true, lineItems: true },
  });
  if (!po) return { error: "PO not found" };

  const action = withNote ? "approve_with_note" : "approve";
  if (!canPerformAction(po.status, action, session.user.role)) {
    return { error: "You cannot approve this PO." };
  }

  if (!po.vendorId) {
    return { error: "A vendor must be assigned before approving this PO." };
  }

  // Resolve the advance: clamp to [0, total]. Undefined ⇒ no explicit advance
  // (full payment, current default behaviour). The slider always sends a value,
  // but a malformed/over-total amount is clamped rather than rejected.
  const total = Number(po.totalAmount);
  const advance =
    parsed.data.suggestedAdvancePayment === undefined
      ? null
      : Math.min(Math.max(parsed.data.suggestedAdvancePayment, 0), total);

  await db.purchaseOrder.update({
    where: { id: poId },
    data: {
      status: "MGR_APPROVED",
      approvedAt: new Date(),
      managerNote: note ?? null,
      suggestedAdvancePayment: advance,
      actions: {
        create: {
          actionType: withNote ? "APPROVED_WITH_NOTE" : "APPROVED",
          note: note ?? null,
          actorId: session.user.id,
          metadata: advance !== null ? { suggestedAdvancePayment: advance } : undefined,
        },
      },
    },
  });

  // Add line items to site inventory immediately on approval (not on closure)
  const siteId = po.siteId ?? null;
  if (siteId) {
    for (const li of po.lineItems) {
      if (!li.productId) continue;
      await db.itemInventory.upsert({
        where: { productId_siteId: { productId: li.productId, siteId } },
        update: { quantity: { increment: Number(li.quantity) } },
        create: { productId: li.productId, siteId, quantity: Number(li.quantity) },
      });
    }
    revalidatePath(`/admin/sites/${siteId}`);
  }

  // Register the line items in the product catalogue (/catalogue/items) on
  // approval, so an approved PO's items are immediately reusable in further POs.
  // Idempotent; payment re-syncs to refresh prices on the final figures.
  await syncProductCatalog(poId, po.lineItems, po.vendorId, session.user.id);
  revalidatePath("/catalogue/items");

  const accounts = await db.user.findMany({ where: { role: "ACCOUNTS", isActive: true } });
  await notify({
    event: withNote ? "PO_APPROVED_WITH_NOTE" : "PO_APPROVED",
    po,
    recipients: [po.submitter, ...accounts],
    note,
  });

  revalidatePath("/approvals");
  revalidatePath(`/po/${poId}`);
  return { ok: true };
}

export async function rejectPo({
  poId,
  note,
}: {
  poId: string;
  note: string;
}): Promise<ActionResult> {
  const session = await auth();
  if (!session?.user) return { error: "Unauthorized" };

  const po = await db.purchaseOrder.findUnique({
    where: { id: poId },
    include: { submitter: true },
  });
  if (!po) return { error: "PO not found" };
  if (!canPerformAction(po.status, "reject", session.user.role)) {
    return { error: "You cannot reject this PO." };
  }

  await db.purchaseOrder.update({
    where: { id: poId },
    data: {
      status: "REJECTED",
      managerNote: note,
      actions: {
        create: { actionType: "REJECTED", note, actorId: session.user.id },
      },
    },
  });

  await notify({ event: "PO_REJECTED", po, recipients: [po.submitter], note });

  revalidatePath("/approvals");
  revalidatePath(`/po/${poId}`);
  return { ok: true };
}

export async function requestEdits({
  poId,
  note,
}: {
  poId: string;
  note: string;
}): Promise<ActionResult> {
  const session = await auth();
  if (!session?.user) return { error: "Unauthorized" };

  const po = await db.purchaseOrder.findUnique({
    where: { id: poId },
    include: { submitter: true },
  });
  if (!po) return { error: "PO not found" };
  if (!canPerformAction(po.status, "request_edits", session.user.role)) {
    return { error: "You cannot request edits on this PO." };
  }

  await db.purchaseOrder.update({
    where: { id: poId },
    data: {
      status: "EDITS_REQUESTED",
      managerNote: note,
      actions: {
        create: { actionType: "EDITS_REQUESTED", note, actorId: session.user.id },
      },
    },
  });

  await notify({ event: "EDITS_REQUESTED", po, recipients: [po.submitter], note });

  revalidatePath("/approvals");
  revalidatePath(`/po/${poId}`);
  return { ok: true };
}

export async function requestVendorId({ poId }: { poId: string }): Promise<ActionResult> {
  const session = await auth();
  if (!session?.user) return { error: "Unauthorized" };

  const po = await db.purchaseOrder.findUnique({
    where: { id: poId },
    include: { submitter: true },
  });
  if (!po) return { error: "PO not found" };
  if (!canPerformAction(po.status, "request_vendor_id", session.user.role)) {
    return { error: "You cannot request a vendor ID for this PO." };
  }

  await db.purchaseOrder.update({
    where: { id: poId },
    data: {
      status: "VENDOR_ID_PENDING",
      actions: {
        create: { actionType: "VENDOR_ID_REQUESTED", actorId: session.user.id },
      },
    },
  });

  await notify({ event: "VENDOR_ID_REQUESTED", po, recipients: [po.submitter] });

  revalidatePath("/approvals");
  revalidatePath(`/po/${poId}`);
  return { ok: true };
}
