import "server-only";
import { cookies } from "next/headers";
import { inArray } from "drizzle-orm";
import { db } from "@/lib/db/client";
import { storeProducts } from "@/lib/db/schema";

const CART_COOKIE = "og_cart";
const MAX_ITEMS = 20;

export type CartLine = {
  productId: string;
  quantity: number;
};

export type CartItem = {
  productId: string;
  slug: string;
  title: string;
  priceMinor: number;
  currency: string;
  coverImage: string | null;
  memberOnly: boolean;
  stockStatus: string;
  quantity: number;
  lineTotalMinor: number;
};

export type CartSummary = {
  items: CartItem[];
  itemCount: number;
  subtotalMinor: number;
  currency: string;
  hasMemberOnly: boolean;
};

/**
 * Read the cookie and return the raw [{productId, qty}] list. Anything
 * malformed is silently ignored — we never throw from cart reads because
 * every page header queries the cart to render the badge.
 */
export async function readCart(): Promise<CartLine[]> {
  const store = await cookies();
  const raw = store.get(CART_COOKIE)?.value;
  if (!raw) return [];
  try {
    const parsed = JSON.parse(raw) as unknown;
    if (!Array.isArray(parsed)) return [];
    return parsed
      .filter(
        (r): r is CartLine =>
          typeof r === "object" &&
          r !== null &&
          typeof (r as CartLine).productId === "string" &&
          typeof (r as CartLine).quantity === "number",
      )
      .filter((r) => r.quantity > 0 && r.quantity <= 100)
      .slice(0, MAX_ITEMS);
  } catch {
    return [];
  }
}

export async function writeCart(lines: CartLine[]): Promise<void> {
  const store = await cookies();
  const sane = lines
    .filter((l) => l.quantity > 0 && l.quantity <= 100)
    .slice(0, MAX_ITEMS);
  if (sane.length === 0) {
    store.delete(CART_COOKIE);
    return;
  }
  store.set(CART_COOKIE, JSON.stringify(sane), {
    httpOnly: false,
    secure: process.env.NODE_ENV === "production",
    sameSite: "lax",
    path: "/",
    maxAge: 60 * 60 * 24 * 30,
  });
}

export async function clearCart(): Promise<void> {
  const store = await cookies();
  store.delete(CART_COOKIE);
}

/**
 * Hydrate the cookie cart into a product-aware summary. Drops any productId
 * that no longer exists (admin deleted it) rather than erroring.
 */
export async function loadCartSummary(): Promise<CartSummary> {
  const lines = await readCart();
  if (lines.length === 0) {
    return {
      items: [],
      itemCount: 0,
      subtotalMinor: 0,
      currency: "GBP",
      hasMemberOnly: false,
    };
  }
  const ids = lines.map((l) => l.productId);
  const rows = await db
    .select({
      id: storeProducts.id,
      slug: storeProducts.slug,
      title: storeProducts.title,
      priceMinor: storeProducts.priceMinor,
      currency: storeProducts.currency,
      coverImage: storeProducts.coverImage,
      memberOnly: storeProducts.memberOnly,
      stockStatus: storeProducts.stockStatus,
      status: storeProducts.status,
    })
    .from(storeProducts)
    .where(inArray(storeProducts.id, ids));
  const byId = new Map(rows.map((r) => [r.id, r]));
  const items: CartItem[] = [];
  let currency = "GBP";
  let subtotal = 0;
  let hasMemberOnly = false;
  for (const l of lines) {
    const p = byId.get(l.productId);
    if (!p || p.status !== "published") continue;
    const lineTotal = p.priceMinor * l.quantity;
    currency = p.currency;
    subtotal += lineTotal;
    if (p.memberOnly) hasMemberOnly = true;
    items.push({
      productId: p.id,
      slug: p.slug,
      title: p.title,
      priceMinor: p.priceMinor,
      currency: p.currency,
      coverImage: p.coverImage,
      memberOnly: p.memberOnly,
      stockStatus: p.stockStatus,
      quantity: l.quantity,
      lineTotalMinor: lineTotal,
    });
  }
  return {
    items,
    itemCount: items.reduce((a, i) => a + i.quantity, 0),
    subtotalMinor: subtotal,
    currency,
    hasMemberOnly,
  };
}

export function formatMinor(minor: number, currency = "GBP"): string {
  return new Intl.NumberFormat("en-GB", {
    style: "currency",
    currency,
  }).format(minor / 100);
}
