"use server";

/**
 * Public storefront data accessors.
 *
 * Each function hits Postgres directly via the shared `pg` pool from
 * `@/lib/db` and is safe to call from public (unauthenticated) pages
 * because the SQL filters by `is_public = true` / `active = true` and
 * never returns anything the storefront shouldn't expose.
 */

import { pool } from "@/lib/db";
import { getSession } from "@/lib/auth";

export type StorefrontBrand = {
  id: string;
  name: string;
  slug: string;
};

export type StorefrontStop = {
  id: string;
  brand_id: string;
  name: string | null;
  city: string;
  state: string;
  zip: string | null;
  address: string | null;
  location: string | null;
  date: string;
  time: string | null;
  cutoff_date: string | null;
  status: string;
  notes: string | null;
  is_public: boolean;
};

export type StorefrontProduct = {
  id: string;
  brand_id: string;
  name: string;
  description: string | null;
  price: number;
  type: string | null;
  image_url: string | null;
  is_taxable: boolean | null;
  pickup_type: string | null;
  active: boolean;
};

export type StorefrontData = {
  brand: StorefrontBrand | null;
  stops: StorefrontStop[];
  products: StorefrontProduct[];
};

/**
 * Look up a brand by its public slug. Returns `null` if no brand matches
 * (which means the storefront slug is wrong, or the brand was renamed).
 */
async function getStorefrontBrandBySlug(
  slug: string,
): Promise<StorefrontBrand | null> {

await getSession();  const { rows } = await pool.query<StorefrontBrand>(
    `SELECT id, name, slug
     FROM brands
     WHERE slug = $1
     LIMIT 1`,
    [slug],
  );
  return rows[0] ?? null;
}

/**
 * Public stops for a brand storefront. Filters out draft / private stops
 * and any stop whose date has already passed.
 */
async function getStorefrontStops(brandId: string): Promise<StorefrontStop[]> {

await getSession();  const { rows } = await pool.query<StorefrontStop>(
    `SELECT id, brand_id, name, city, state, zip, address, location,
            date::text AS date, time, cutoff_date::text AS cutoff_date,
            status, notes, is_public
     FROM stops
     WHERE brand_id = $1
       AND is_public = true
       AND status = 'active'
       AND date >= CURRENT_DATE
     ORDER BY date ASC, time ASC NULLS LAST`,
    [brandId],
  );
  return rows;
}

/**
 * Active products visible on the storefront. Same shape as the admin
 * product list but without the brand-internal columns (cost, supplier, …).
 *
 * Note: products.price is stored in cents (NUMERIC). We return it as a
 * float in **dollars** so callers can format directly as `$${price}`
 * without doing the cents-to-dollars math.
 */
async function getStorefrontProducts(
  brandId: string,
): Promise<StorefrontProduct[]> {

await getSession();  const { rows } = await pool.query<StorefrontProduct>(
    `SELECT id, brand_id, name, description,
            price::float8 / 100 AS price,
            type, image_url, is_taxable, pickup_type, active
     FROM products
     WHERE brand_id = $1
       AND active = true
       AND deleted_at IS NULL
     ORDER BY name ASC`,
    [brandId],
  );
  return rows;
}

/**
 * Single server action that the storefront Client Components call from
 * their initial `useEffect`. Bundles brand lookup + public stops +
 * active products into one round-trip-friendly call.
 *
 * Returns `{ brand: null, stops: [], products: [] }` if the slug doesn't
 * match any brand — pages fall back to default copy in that case.
 */
async function getStorefrontData(slug: string): Promise<StorefrontData> {

await getSession();  const brand = await getStorefrontBrandBySlug(slug);
  if (!brand) return { brand: null, stops: [], products: [] };
  const [stops, products] = await Promise.all([
    getStorefrontStops(brand.id),
    getStorefrontProducts(brand.id),
  ]);
  return { brand, stops, products };
}

export type StorefrontWholesaleSettings = {
  invoice_business_name: string | null;
};

/**
 * Public wholesale-settings record for a brand — just the invoice
 * business name used by the storefront contact page. Returns `null`
 * if the brand or its wholesale settings row doesn't exist.
 *
 * NOTE: only `invoice_business_name` is exposed; other invoice-contact
 * fields don't exist on `wholesale_settings` yet and shouldn't be
 * surfaced here. If you need them, add a migration first.
 */
async function getStorefrontWholesaleSettings(
  slug: string,
): Promise<StorefrontWholesaleSettings | null> {

await getSession();  const brand = await getStorefrontBrandBySlug(slug);
  if (!brand) return null;
  const { rows } = await pool.query<StorefrontWholesaleSettings>(
    `SELECT invoice_business_name
     FROM wholesale_settings
     WHERE brand_id = $1
     LIMIT 1`,
    [brand.id],
  );
  return rows[0] ?? null;
}

export type WholesalePortalConfig = {
  wholesale_enabled: boolean | null;
  online_payment_enabled: boolean | null;
};

/**
 * Public wholesale portal flags for a brand. Used by the customer-facing
 * `/wholesale/portal` page to decide whether to allow sign-in and whether
 * to show the online-payment button. Doesn't require auth (the portal
 * already validated the session before this is called).
 */
async function getWholesalePortalConfig(
  brandId: string,
): Promise<WholesalePortalConfig | null> {

await getSession();  const { rows } = await pool.query<WholesalePortalConfig>(
    `SELECT wholesale_enabled, online_payment_enabled
     FROM wholesale_settings
     WHERE brand_id = $1
     LIMIT 1`,
    [brandId],
  );
  return rows[0] ?? null;
}

export type BrandName = { name: string };

/**
 * Fetch a brand's display name by id. Public — used by the wholesale
 * portal header to render the brand name without leaking any other
 * brand columns (logo, plan, stripe keys, etc.).
 */
async function getStorefrontBrandName(
  brandId: string,
): Promise<string | null> {

await getSession();  const { rows } = await pool.query<BrandName>(
    `SELECT name FROM brands WHERE id = $1 LIMIT 1`,
    [brandId],
  );
  return rows[0]?.name ?? null;
}

/**
 * Look up a single public stop by its id, plus the brand's active
 * products. Used by `/[brand]/stops/[id]` pages.
 *
 * NOTE: The URL parameter is named `[id]` (not `[slug]`) because the
 * `stops` table has no slug column. URLs use the stop's UUID.
 *
 * Returns `null` if the stop is not public, not active, or its date has
 * already passed. Returns the empty product array if the brand has no
 * active products at the moment.
 */
export async function getStorefrontStopById(id: string): Promise<{
  stop: StorefrontStop;
  products: StorefrontProduct[];
} | null> {

await getSession();  const { rows: stopRows } = await pool.query<StorefrontStop>(
    `SELECT id, brand_id, name, city, state, zip, address, location,
            date::text AS date, time, cutoff_date::text AS cutoff_date,
            status, notes, is_public
     FROM stops
     WHERE id = $1
       AND is_public = true
       AND status = 'active'
     LIMIT 1`,
    [id],
  );
  const stop = stopRows[0];
  if (!stop) return null;
  const products = await getStorefrontProducts(stop.brand_id);
  return { stop, products };
}