import type { StoreSiteBlock } from "@alqove/api-client";
import { api } from "@/lib/api";
import { blockData, list, num, str } from "./block-data";
import { blockKey } from "./block-key";

export interface StorefrontProduct {
  id: string;
  title: string;
  brand: string | null;
  price: number;
  condition: string | null;
  imageUrl: string | null;
}

export const MAX_PRODUCTS_PER_BLOCK = 24;

export function productLimit(block: StoreSiteBlock): number {
  return Math.min(Math.max(num(blockData(block), "limit", 8), 1), MAX_PRODUCTS_PER_BLOCK);
}

/**
 * Resolve one `products` block's query against the public item search. Blocks
 * store a query rather than resolved listings, so a storefront never shows
 * stock the store has already sold.
 */
export async function loadBlockProducts(
  block: StoreSiteBlock,
  storeId: string,
): Promise<StorefrontProduct[]> {
  const data = blockData(block);
  const source = str(data, "source") ?? "newest";
  const limit = productLimit(block);

  if (source === "picked") {
    const ids = list<string>(data, "item_ids")
      .filter((id): id is string => typeof id === "string")
      .slice(0, limit);

    const results = await Promise.all(ids.map((id) => loadOneProduct(id)));

    // A picked item that has since sold or been removed drops out of the grid
    // rather than failing the page.
    return results.filter((p): p is StorefrontProduct => p !== null);
  }

  const categorySlug = source === "category" ? str(data, "category_slug") : null;

  try {
    const res = await api.items.browse({
      store_id: [storeId],
      per_page: limit,
      sort: "newest",
      ...(categorySlug ? { category_slug: categorySlug } : {}),
    });

    return (res.data ?? []).slice(0, limit).map((item) => ({
      id: item.id ?? "",
      title: item.title ?? "",
      brand: item.brand ?? null,
      price: item.price ?? 0,
      condition: item.condition ?? null,
      imageUrl: item.thumbnail_url ?? null,
    }));
  } catch {
    // A storefront that can't reach search still renders its other blocks.
    return [];
  }
}

async function loadOneProduct(id: string): Promise<StorefrontProduct | null> {
  try {
    const res = await api.items.getPublic(id);
    const item = res.data;

    // The detail endpoint returns the full image set; the grid wants one
    // thumbnail, and images are already ordered.
    const primary = item.images?.[0];

    return {
      id: item.id ?? id,
      title: item.title ?? "",
      brand: item.brand ?? null,
      price: item.price ?? 0,
      condition: item.condition ?? null,
      imageUrl: primary?.thumb ?? primary?.url ?? null,
    };
  } catch {
    return null;
  }
}

/**
 * Resolve every `products` block on a page, keyed by block id. Blocks are
 * fetched concurrently so a page with several grids costs one round-trip's
 * latency, not one per grid.
 */
export async function loadProductsForBlocks(
  blocks: StoreSiteBlock[] | null | undefined,
  storeId: string | null | undefined,
): Promise<Record<string, StorefrontProduct[]>> {
  if (!storeId) return {};

  // Index is taken from the full block list so the key matches the renderer's
  // fallback key for a block that somehow arrived without an id.
  const productBlocks = (blocks ?? [])
    .map((block, index) => ({ block, index }))
    .filter(({ block }) => block.type === "products");

  if (productBlocks.length === 0) return {};

  const resolved = await Promise.all(
    productBlocks.map(async ({ block, index }) => {
      return [blockKey(block, index), await loadBlockProducts(block, storeId)] as const;
    }),
  );

  return Object.fromEntries(resolved);
}
