import "server-only";
import type { Prisma } from "@prisma/client";
import { db } from "./db";
import { batchState, remainingCapacity, type BatchState } from "./preorder";

export const productCardInclude = {
  images: { orderBy: { sortOrder: "asc" }, take: 2 },
  category: { select: { slug: true, name: true } },
  variants: { where: { active: true }, include: { batch: true }, orderBy: { sortOrder: "asc" } },
} satisfies Prisma.ProductInclude;

export type CardProduct = Prisma.ProductGetPayload<{ include: typeof productCardInclude }>;

export type Availability = {
  mode: "READY_STOCK" | "PRE_ORDER";
  state: "IN_STOCK" | "LOW_STOCK" | "SOLD_OUT" | BatchState;
  label: string;
  purchasable: boolean;
};

/** Availability for a single variant, from live DB values. */
export function variantAvailability(v: CardProduct["variants"][number], now = new Date()): Availability {
  if (v.mode === "PRE_ORDER") {
    if (!v.batch) return { mode: "PRE_ORDER", state: "CLOSED", label: "Pre-order not configured", purchasable: false };
    const st = batchState(v.batch, now);
    const label = { OPEN: "Pre-order", SCHEDULED: "Opens soon", CLOSED: "Pre-order closed", SOLD_OUT: "Fully reserved" }[st];
    return { mode: "PRE_ORDER", state: st, label, purchasable: st === "OPEN" };
  }
  if (v.stockQty <= 0) return { mode: "READY_STOCK", state: "SOLD_OUT", label: "Sold out", purchasable: false };
  if (v.stockQty <= 3) return { mode: "READY_STOCK", state: "LOW_STOCK", label: `Only ${v.stockQty} left`, purchasable: true };
  return { mode: "READY_STOCK", state: "IN_STOCK", label: "Ready to ship", purchasable: true };
}

/** Summary for a product card: pre-order wins if any variant is a pre-order. */
export function productAvailability(p: CardProduct, now = new Date()): Availability {
  const av = p.variants.map((v) => variantAvailability(v, now));
  if (!av.length) return { mode: "READY_STOCK", state: "SOLD_OUT", label: "Unavailable", purchasable: false };
  const buyable = av.find((a) => a.purchasable);
  if (buyable) return av.some((a) => a.mode === "PRE_ORDER" && a.purchasable) ? av.find((a) => a.mode === "PRE_ORDER" && a.purchasable)! : buyable;
  return av.find((a) => a.state === "SCHEDULED") ?? av[0];
}

export function priceRange(p: CardProduct) {
  const prices = p.variants.map((v) => v.price ?? p.basePrice);
  if (!prices.length) return { min: p.basePrice, max: p.basePrice };
  return { min: Math.min(...prices), max: Math.max(...prices) };
}

export function batchCapacityInfo(b: { capacity: number; heldQty: number; committedQty: number }) {
  return { remaining: remainingCapacity(b), reserved: b.heldQty + b.committedQty, capacity: b.capacity };
}

export type SortKey = "featured" | "newest" | "price-asc" | "price-desc";

export async function listProducts(opts: {
  categorySlug?: string;
  collectionSlug?: string;
  q?: string;
  availability?: "ready" | "preorder";
  colour?: string;
  size?: string;
  min?: number;
  max?: number;
  sort?: SortKey;
  take?: number;
}) {
  const where: Prisma.ProductWhereInput = { status: "PUBLISHED" };
  if (opts.categorySlug) where.category = { slug: opts.categorySlug };
  if (opts.collectionSlug) where.collections = { some: { collection: { slug: opts.collectionSlug } } };
  if (opts.q) {
    where.OR = [{ name: { contains: opts.q } }, { shortDescription: { contains: opts.q } }, { sku: { contains: opts.q } }, { category: { name: { contains: opts.q } } }];
  }
  const vWhere: Prisma.ProductVariantWhereInput = { active: true };
  if (opts.availability === "ready") vWhere.mode = "READY_STOCK";
  if (opts.availability === "preorder") vWhere.mode = "PRE_ORDER";
  if (opts.colour) vWhere.color = opts.colour;
  if (opts.size) vWhere.size = opts.size;
  if (opts.availability || opts.colour || opts.size) where.variants = { some: vWhere };
  if (opts.min != null || opts.max != null) where.basePrice = { gte: opts.min ?? undefined, lte: opts.max ?? undefined };

  const orderBy: Prisma.ProductOrderByWithRelationInput[] =
    opts.sort === "newest" ? [{ createdAt: "desc" }]
    : opts.sort === "price-asc" ? [{ basePrice: "asc" }]
    : opts.sort === "price-desc" ? [{ basePrice: "desc" }]
    : [{ featured: "desc" }, { sortOrder: "asc" }, { createdAt: "desc" }];

  return db.product.findMany({ where, orderBy, include: productCardInclude, take: opts.take });
}

export async function facetValues(categorySlug?: string) {
  const variants = await db.productVariant.findMany({
    where: { active: true, product: { status: "PUBLISHED", ...(categorySlug ? { category: { slug: categorySlug } } : {}) } },
    select: { color: true, size: true },
  });
  const colours = [...new Set(variants.map((v) => v.color).filter(Boolean))] as string[];
  const order = ["XS", "S", "M", "L", "XL", "XXL"];
  const sizes = ([...new Set(variants.map((v) => v.size).filter(Boolean))] as string[]).sort((a, b) => order.indexOf(a) - order.indexOf(b));
  return { colours: colours.sort(), sizes };
}
