import type { LoaderFunctionArgs } from "react-router";
import { unauthenticated } from "../shopify.server";
import db from "../db.server";
import { buildGiroCodePngBuffer } from "../services/invoice/girocode";
import { verifyGiroCodeUrl } from "../services/invoice/signedUrl";
import { resolveOrderRemittance } from "../services/invoice/remittance.server";

/**
 * Public PNG endpoint that returns the GiroCode QR image bytes for an order.
 * Auth: short-lived HMAC-signed URL (issued by /api/public/payment-info).
 *
 * Required query params: shop, orderId, exp, sig.
 */
export const loader = async ({ request }: LoaderFunctionArgs) => {
  const url = new URL(request.url);
  const verified = verifyGiroCodeUrl(url.searchParams);
  if (!verified.ok) {
    return new Response(`unauthorized: ${verified.reason ?? "invalid"}`, { status: 401 });
  }
  const { shop, orderId } = verified;
  if (!shop || !orderId) {
    return new Response("bad request", { status: 400 });
  }

  const settings = await db.shopSettings.findUnique({ where: { shopDomain: shop } });
  if (!settings?.iban) {
    return new Response("not found", { status: 404 });
  }

  // Recompute payload server-side from order + settings (don't trust client).
  const numericId = orderId.replace(/[^0-9]/g, "");
  const orderGid = `gid://shopify/Order/${numericId}`;

  const { admin } = await unauthenticated.admin(shop);
  const res = await admin.graphql(
    `#graphql
    query GiroCodeOrderInfo($id: ID!) {
      order(id: $id) {
        name
        number
        currencyCode
        totalPriceSet { shopMoney { amount } }
        totalOutstandingSet { shopMoney { amount } }
      }
    }`,
    { variables: { id: orderGid } },
  );
  const json = (await res.json()) as {
    data?: {
      order?: {
        name?: string;
        number?: number | null;
        currencyCode?: string;
        totalPriceSet?: { shopMoney: { amount: string } };
        totalOutstandingSet?: { shopMoney: { amount: string } };
      } | null;
    };
  };
  const o = json.data?.order;
  if (!o) {
    return new Response("not found", { status: 404 });
  }

  const total = parseFloat(o.totalPriceSet?.shopMoney.amount ?? "0");
  const outstanding = parseFloat(o.totalOutstandingSet?.shopMoney.amount ?? "0");
  const amount = outstanding > 0 ? outstanding : total;
  // Use the canonical invoice number printed on the PDF — keeping the QR
  // and the customer-facing thank-you/account page in lockstep so the
  // bank treats both as one and the same payment.
  const remittance = await resolveOrderRemittance({
    shopDomain: shop,
    orderGid,
    orderNumber: typeof o.number === "number" ? o.number : null,
    settings,
  });

  const png = await buildGiroCodePngBuffer({
    beneficiaryName: [settings.companyName, settings.legalForm].filter(Boolean).join(" "),
    iban: settings.iban,
    bic: settings.bic,
    amount,
    currency: o.currencyCode ?? "EUR",
    remittance,
  });

  const body = new Uint8Array(png);
  return new Response(body, {
    status: 200,
    headers: {
      "Content-Type": "image/png",
      "Cache-Control": "private, max-age=300",
      // No CORS header: the PNG is rendered via an <s-image> tag in the
      // checkout/customer-account extensions (see extensions/*/src/*.tsx),
      // i.e. a plain image load, which is not subject to CORS. Dropping the
      // previous `Access-Control-Allow-Origin: *` removes the ability for any
      // origin to fetch() these bytes cross-origin while keeping the
      // legitimate <img>-style loads working.
    },
  });
};
