import type { ActionFunctionArgs, LoaderFunctionArgs } from "react-router";
import { authenticate } from "../shopify.server";
import db from "../db.server";
import { generateInvoice } from "../services/invoice/generateInvoice.server";
import { cancelAndReissue } from "../services/invoice/cancelAndReissue.server";

/**
 * GET  /api/orders/:orderId/invoice  → returns latest invoice metadata + history
 * POST /api/orders/:orderId/invoice  → generates (or regenerates) the invoice
 *
 * `orderId` may be a numeric Shopify order id or a full GID; the generator
 * normalises it.
 */
export const loader = async ({ request, params }: LoaderFunctionArgs) => {
  const { session, cors } = await authenticate.admin(request);
  const orderId = requireOrderId(params);
  const orderGid = orderId.startsWith("gid://")
    ? orderId
    : `gid://shopify/Order/${orderId}`;

  const invoices = await db.invoice.findMany({
    where: { shopDomain: session.shop, orderId: orderGid },
    orderBy: [{ issuedAt: "desc" }],
  });
  const latest = invoices.find((i) => i.kind === "invoice" && !i.cancelledAt);

  return cors(
    Response.json({
      latest: latest ? serialise(latest) : null,
      history: invoices.map(serialise),
    }),
  );
};

export const action = async ({ request, params }: ActionFunctionArgs) => {
  const { admin, session, cors } = await authenticate.admin(request);
  if (request.method !== "POST") {
    return cors(new Response("Method Not Allowed", { status: 405 }));
  }
  const orderId = requireOrderId(params);
  const url = new URL(request.url);
  let op = url.searchParams.get("action");
  if (!op) {
    // Also accept the action from the form body (used by the in-app fetcher).
    const ct = request.headers.get("content-type") || "";
    if (ct.includes("application/x-www-form-urlencoded") || ct.includes("multipart/form-data")) {
      const form = await request.formData();
      op = (form.get("action") as string | null) ?? null;
    }
  }
  op = op ?? "generate";

  try {
    if (op === "cancel_reissue") {
      const result = await cancelAndReissue({
        shopDomain: session.shop,
        admin,
        orderId,
      });
      return cors(Response.json({ ok: true, op, ...result }));
    }

    const result = await generateInvoice({
      shopDomain: session.shop,
      admin,
      orderId,
    });
    return cors(Response.json({ ok: true, op: "generate", ...result }));
  } catch (err) {
    const message = err instanceof Error ? err.message : String(err);
    console.error("invoice action failed:", err);
    return cors(Response.json({ ok: false, error: message }, { status: 400 }));
  }
};

function requireOrderId(params: { orderId?: string }): string {
  const id = params.orderId;
  if (!id) throw new Response("orderId is required", { status: 400 });
  return id;
}

function serialise(invoice: {
  id: string;
  invoiceNumber: string;
  version: number;
  kind: string;
  pdfUrl: string;
  status: string;
  sentAt: Date | null;
  cancelledAt: Date | null;
  issuedAt: Date;
}) {
  return {
    id: invoice.id,
    invoiceNumber: invoice.invoiceNumber,
    version: invoice.version,
    kind: invoice.kind,
    pdfUrl: invoice.pdfUrl,
    status: invoice.status,
    sentAt: invoice.sentAt?.toISOString() ?? null,
    cancelledAt: invoice.cancelledAt?.toISOString() ?? null,
    issuedAt: invoice.issuedAt.toISOString(),
  };
}
