import { formatPrice } from "./format";

// Server-only — imported exclusively by app/api/discount/*/route.ts (Route
// Handlers are never bundled for the client anyway, but this file also
// touches DISCOUNT_SERVICE_SECRET, which must never end up reachable from
// a "use client" import graph). Kept out of lib/payload.ts on purpose,
// same reasoning as that file's own comment about staying free of
// next/headers — a shared module used by both server and client code is
// exactly where an accidental server-only dependency causes a build break.
const PAYLOAD_URL = process.env.PAYLOAD_URL || "https://payload.mk360.de";
const TENANT_SLUG = "einfach-produktiv";
const SERVICE_SECRET = process.env.DISCOUNT_SERVICE_SECRET || "";

type PayloadDiscountCode = {
  id: number;
  code: string;
  type: "percent" | "fixed";
  value: number;
  validFrom: string | null;
  validUntil: string | null;
  minOrderValue: number | null;
  maxRedemptions: number | null;
  redemptionCount: number;
  active: boolean;
};

async function fetchDiscountCode(code: string): Promise<PayloadDiscountCode | null> {
  const params = new URLSearchParams({
    "where[tenant.slug][equals]": TENANT_SLUG,
    "where[code][equals]": code.toUpperCase().trim(),
    limit: "1",
  });

  const res = await fetch(`${PAYLOAD_URL}/api/discount-codes?${params}`, {
    headers: { "x-discount-service-secret": SERVICE_SECRET },
    cache: "no-store",
  });
  if (!res.ok) {
    console.error(`fetchDiscountCode: Payload returned ${res.status} ${res.statusText}`);
    return null;
  }

  const data: { docs?: PayloadDiscountCode[] } = await res.json();
  return data.docs?.[0] ?? null;
}

// Whether it's worth showing the cart's manual "Rabattcode" input field at
// all — no point offering an open text field for a shopper to type into
// when there's nothing in Payload that could ever validate. Existence-only
// check (active: true), not the fuller validFrom/validUntil/minOrderValue
// window validateDiscountCode() does for an actual submitted code — this
// just gates whether the field renders, the real validation still happens
// at apply time regardless.
export async function hasActiveDiscountCode(): Promise<boolean> {
  const params = new URLSearchParams({
    "where[tenant.slug][equals]": TENANT_SLUG,
    "where[active][equals]": "true",
    limit: "1",
  });
  const res = await fetch(`${PAYLOAD_URL}/api/discount-codes?${params}`, {
    headers: { "x-discount-service-secret": SERVICE_SECRET },
    next: { revalidate: 60 },
  });
  if (!res.ok) {
    console.error(`hasActiveDiscountCode: Payload returned ${res.status} ${res.statusText}`);
    return false;
  }
  const data: { docs?: unknown[] } = await res.json();
  return (data.docs?.length ?? 0) > 0;
}

export type DiscountValidation =
  | { valid: true; doc: PayloadDiscountCode }
  | { valid: false; reason: string };

// Shared by both routes below — /validate calls this read-only when a
// shopper applies a code in the cart; /redeem calls it again immediately
// before incrementing the counter (the window/limit may have changed
// between the two, however unlikely), so neither route duplicates these
// rules independently.
export async function validateDiscountCode(code: string, subtotal: number): Promise<DiscountValidation> {
  const doc = await fetchDiscountCode(code);
  if (!doc) return { valid: false, reason: "Dieser Code existiert nicht." };
  if (!doc.active) return { valid: false, reason: "Dieser Code ist nicht mehr gültig." };

  const now = Date.now();
  if (doc.validFrom && now < new Date(doc.validFrom).getTime()) {
    return { valid: false, reason: "Dieser Code ist noch nicht gültig." };
  }
  if (doc.validUntil && now > new Date(doc.validUntil).getTime()) {
    return { valid: false, reason: "Dieser Code ist abgelaufen." };
  }
  if (doc.minOrderValue != null && subtotal < doc.minOrderValue) {
    return { valid: false, reason: `Dieser Code gilt erst ab einem Bestellwert von ${formatPrice(doc.minOrderValue)}.` };
  }
  if (doc.maxRedemptions != null && doc.redemptionCount >= doc.maxRedemptions) {
    return { valid: false, reason: "Dieser Code wurde bereits zu oft eingelöst." };
  }

  return { valid: true, doc };
}

// Read-then-write, not an atomic conditional update — a true concurrent
// race on the very last redemption of a capped code has a narrow window
// where two requests could both pass validateDiscountCode() before either
// increments. Accepted, not worth custom atomic SQL for this shop's
// traffic level.
export async function redeemDiscountCode(doc: PayloadDiscountCode): Promise<boolean> {
  const res = await fetch(`${PAYLOAD_URL}/api/discount-codes/${doc.id}`, {
    method: "PATCH",
    headers: {
      "x-discount-service-secret": SERVICE_SECRET,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ redemptionCount: doc.redemptionCount + 1 }),
  });
  if (!res.ok) {
    console.error(`redeemDiscountCode: Payload returned ${res.status} ${res.statusText}`);
  }
  return res.ok;
}
