// Server-only — imported exclusively by app/api/checkout/route.ts. Kept
// out of lib/payload.ts on purpose, same reasoning as discountServer.ts's
// own comment about staying free of next/headers in a module that's also
// reachable from "use client" import graphs.
const PAYLOAD_URL = process.env.PAYLOAD_URL || "https://payload.mk360.de";
const TENANT_SLUG = "einfach-produktiv";
const SERVICE_SECRET = process.env.ORDER_SERVICE_SECRET || "";

// Resolved once per request rather than cached across requests — this
// instance only has 1 tenant today, but a module-level cache would be the
// kind of thing that silently goes stale the moment a second tenant shows
// up. Cheap enough (single indexed lookup) not to worry about at this
// traffic level.
async function resolveTenantId(): Promise<number | null> {
  const params = new URLSearchParams({ "where[slug][equals]": TENANT_SLUG, limit: "1" });
  const res = await fetch(`${PAYLOAD_URL}/api/tenants?${params}`, { cache: "no-store" });
  if (!res.ok) return null;
  const data: { docs?: { id: number }[] } = await res.json();
  return data.docs?.[0]?.id ?? null;
}

export type OrderItemInput = {
  productId: number;
  productName: string;
  quantity: number;
  unitPrice: number;
  taxRatePercent: number;
  bundleContents: string | null;
  variantName: string | null;
  // Resolved by the caller (api/checkout/route.ts): the variant's own sku
  // if one was selected, else the product's sku, else null — same
  // "variant overrides product" precedence as unitPrice/taxRatePercent
  // elsewhere in this checkout flow.
  sku: string | null;
};

export type CreateOrderInput = {
  customerId: number;
  customerFirstName: string;
  customerLastName: string;
  customerEmail: string;
  // Optional B2B snapshot fields — see Orders.ts's own comment on why both
  // are independently optional.
  companyName?: string;
  vatId?: string;
  // Decided server-side in api/checkout/route.ts (a live VIES check at the
  // moment of purchase, never guessed) — see Orders.ts's own comment.
  vatExempt: boolean;
  // §19 UStG — this tenant's company-settings.kleinunternehmer as read at
  // the moment of purchase, snapshotted onto the order (same reasoning as
  // vatExempt above, plus Orders.ts's own field comment).
  kleinunternehmer: boolean;
  vatIdValidatedAt: string | null;
  deliveryMethod: "address" | "packstation";
  street?: string;
  packstationNumber?: string;
  postNumber?: string;
  zip: string;
  city: string;
  country: string;
  // Optional package destination distinct from the billing address above
  // — mirrors Orders.ts's own shipping*/hasDifferentShippingAddress
  // fields exactly, just camelCased the same way the rest of this input
  // type already is.
  hasDifferentShippingAddress?: boolean;
  shippingFirstName?: string;
  shippingLastName?: string;
  shippingDeliveryMethod?: "address" | "packstation";
  shippingStreet?: string;
  shippingPackstationNumber?: string;
  shippingPostNumber?: string;
  shippingZip?: string;
  shippingCity?: string;
  shippingCountry?: string;
  // Optional, mirrors companyName above — no shipping-side vatId (billing-
  // only concept). Contact email/phone have no billing-side equivalent:
  // they're handed to the shipping carrier, never used for customer
  // communication.
  shippingCompanyName?: string;
  shippingContactEmail?: string;
  shippingContactPhone?: string;
  newsletterOptIn: boolean;
  items: OrderItemInput[];
  subtotal: number;
  shippingCost: number;
  shippingMethodTitle: string;
  // Numeric ShippingMethod id, not the same as shippingMethodTitle's frozen
  // text snapshot — lets pollCarrierTracking.ts resolve order → shipping
  // method → carrier without a fragile title-text match. See Orders.ts's
  // own comment on why both fields exist side by side.
  shippingMethod: number;
  paymentMethodTitle: string;
  discountCode: string | null;
  discountAmount: number;
  total: number;
  // Gated-payment fields (see spicy-leaping-pizza.md §1/§3) — all three
  // omitted for a manual/Überweisung order, which is exactly today's
  // behavior (Orders.ts's own field defaults apply: status 'received',
  // paymentProvider 'manual', paymentStatus 'not_applicable').
  status?: "pending_payment";
  paymentProvider?: "stripe";
  paymentStatus?: "pending";
  // Known before the order is created (Stripe generates a PaymentIntent id
  // immediately, independent of any order existing yet) — persisted at
  // creation time specifically so the expirePendingPayments cleanup job
  // has something to reconcile against even if the webhook metadata
  // round-trip (stripeProvider.attachOrderMetadata) never completes.
  providerReference?: string;
};

export type CreatedOrder = {
  id: number;
  orderNumber: string;
  createdAt: string;
  invoiceNumber: string | null;
  invoiceIssuedAt: string | null;
};

export async function createOrder(input: CreateOrderInput): Promise<CreatedOrder | null> {
  const tenantId = await resolveTenantId();
  if (tenantId == null) {
    console.error("createOrder: could not resolve tenant id");
    return null;
  }

  const res = await fetch(`${PAYLOAD_URL}/api/orders`, {
    method: "POST",
    headers: {
      "x-order-service-secret": SERVICE_SECRET,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      tenant: tenantId,
      customer: input.customerId,
      customerFirstName: input.customerFirstName,
      customerLastName: input.customerLastName,
      customerEmail: input.customerEmail,
      companyName: input.companyName,
      vatId: input.vatId,
      vatExempt: input.vatExempt,
      kleinunternehmer: input.kleinunternehmer,
      vatIdValidatedAt: input.vatIdValidatedAt,
      deliveryMethod: input.deliveryMethod,
      street: input.street,
      packstationNumber: input.packstationNumber,
      postNumber: input.postNumber,
      zip: input.zip,
      city: input.city,
      country: input.country,
      hasDifferentShippingAddress: input.hasDifferentShippingAddress ?? false,
      shippingFirstName: input.shippingFirstName,
      shippingLastName: input.shippingLastName,
      shippingDeliveryMethod: input.shippingDeliveryMethod,
      shippingStreet: input.shippingStreet,
      shippingPackstationNumber: input.shippingPackstationNumber,
      shippingPostNumber: input.shippingPostNumber,
      shippingZip: input.shippingZip,
      shippingCity: input.shippingCity,
      shippingCountry: input.shippingCountry,
      shippingCompanyName: input.shippingCompanyName,
      shippingContactEmail: input.shippingContactEmail,
      shippingContactPhone: input.shippingContactPhone,
      newsletterOptIn: input.newsletterOptIn,
      items: input.items.map((i) => ({
        product: i.productId,
        productName: i.productName,
        quantity: i.quantity,
        unitPrice: i.unitPrice,
        taxRatePercent: i.taxRatePercent,
        bundleContents: i.bundleContents,
        variantName: i.variantName,
        sku: i.sku,
      })),
      subtotal: input.subtotal,
      shippingCost: input.shippingCost,
      shippingMethodTitle: input.shippingMethodTitle,
      shippingMethod: input.shippingMethod,
      paymentMethodTitle: input.paymentMethodTitle,
      discountCode: input.discountCode,
      discountAmount: input.discountAmount,
      total: input.total,
      ...(input.status ? { status: input.status } : {}),
      ...(input.paymentProvider ? { paymentProvider: input.paymentProvider } : {}),
      ...(input.paymentStatus ? { paymentStatus: input.paymentStatus } : {}),
      ...(input.providerReference ? { providerReference: input.providerReference } : {}),
    }),
  });

  if (!res.ok) {
    console.error(`createOrder: Payload returned ${res.status} ${res.statusText}`);
    return null;
  }

  const data: {
    doc: { id: number; orderNumber: string; createdAt: string; invoiceNumber: string | null; invoiceIssuedAt: string | null };
  } = await res.json();
  return {
    id: data.doc.id,
    orderNumber: data.doc.orderNumber,
    createdAt: data.doc.createdAt,
    invoiceNumber: data.doc.invoiceNumber,
    invoiceIssuedAt: data.doc.invoiceIssuedAt,
  };
}
