import { createClient } from "@sanity/client";
import imageUrlBuilder from "@sanity/image-url";
import type { SanityImageSource } from "@sanity/image-url/lib/types/types";

export const projectId =
  process.env.NEXT_PUBLIC_SANITY_PROJECT_ID || "g2e4kxsj";
export const dataset = process.env.NEXT_PUBLIC_SANITY_DATASET || "production";
export const apiVersion =
  process.env.NEXT_PUBLIC_SANITY_API_VERSION || "2024-10-01";

export const client = createClient({
  projectId,
  dataset,
  apiVersion,
  useCdn: true,
  // Only used for private datasets / draft previews. Public datasets need none.
  token: process.env.SANITY_API_READ_TOKEN,
  perspective: "published",
});

const builder = imageUrlBuilder(client);

/**
 * Build a Sanity image-URL builder for a source. Chain transforms on the
 * result, e.g. `urlFor(img).width(800).quality(80).url()`.
 *
 * @param source - A Sanity image reference / asset.
 * @returns An `@sanity/image-url` builder for that source.
 */
export function urlFor(source: SanityImageSource) {
  return builder.image(source);
}

/**
 * Build-time GROQ fetch with a safety net: if the dataset is empty or
 * unreachable, the error is swallowed and `fallback` is returned so the static
 * export still builds (the affected section just renders its empty state).
 *
 * @typeParam T - Expected shape of the query result.
 * @param query - GROQ query string.
 * @param params - Query parameters. Defaults to `{}`.
 * @param fallback - Value returned if the fetch throws. Optional.
 * @returns The query result, or `fallback` on failure.
 */
export async function sanityFetch<T>(
  query: string,
  params: Record<string, unknown> = {},
  fallback?: T,
): Promise<T> {
  try {
    return await client.fetch<T>(query, params);
  } catch (err) {
    console.warn(
      "[sanity] fetch failed, using fallback:",
      (err as Error).message,
    );
    return fallback as T;
  }
}

// `output: export` requires every dynamic route to prerender at least one path.
// A section with no published content yet (or whose last item gets unpublished)
// would otherwise return zero slugs and fail the build with a misleading
// "missing generateStaticParams()" error. Emit a harmless placeholder so the
// export always builds; the detail page 404s for it and real content replaces
// it automatically once published.
export const EMPTY_ROUTE_SLUG = "__none__";

/**
 * Build the `generateStaticParams()` slug list for a dynamic detail route.
 * Always returns at least one entry — {@link EMPTY_ROUTE_SLUG} when a section
 * has no published content yet — so `output: "export"` never fails on a route
 * with zero prerendered paths.
 *
 * @param query - GROQ query returning rows shaped `{ slug: string }`.
 * @returns Slug params for static generation (never empty).
 */
export async function slugStaticParams(
  query: string,
): Promise<{ slug: string }[]> {
  const rows = await sanityFetch<{ slug: string }[]>(query, {}, []);
  const params = rows.filter((s) => s.slug).map((s) => ({ slug: s.slug }));
  return params.length ? params : [{ slug: EMPTY_ROUTE_SLUG }];
}
