import "server-only";

import { isConfigured, readToken } from "./env";
import { getClient } from "./client";

/**
 * Two thin wrappers around `client.fetch` that enforce the Plan 3 fallback
 * rule: when `NEXT_PUBLIC_SANITY_PROJECT_ID` is missing the site must still
 * build and render clean empty states — never a 500.
 *
 * Having two typed wrappers (list vs. single) keeps the call sites honest:
 * list routes get `[] as T[]` on no-env, detail routes get `null`. A single
 * wrapper could not safely cover both without widening the return type and
 * losing type safety at every call site.
 *
 * Caching: fetches use Next.js tag-based revalidation with a 1-hour fallback
 * so the webhook at `/api/revalidate` can surgically invalidate list + detail
 * after publish, while anything we miss still expires in an hour.
 *
 * Preview mode: when `preview === true` and a read token is present, we
 * re-derive a token-authenticated client via `withConfig`, request the
 * `drafts` perspective, and disable the CDN + cache so editors always see
 * the latest unpublished content. Without a token we silently fall through
 * to the published path — preview only works when Sanity credentials
 * include a token with draft access.
 */

type FetchArgs = {
  query: string;
  params?: Record<string, unknown>;
  tags: string[];
  preview?: boolean;
};

function resolveClient(preview: boolean) {
  const base = getClient();
  if (preview && readToken) {
    return base.withConfig({
      token: readToken,
      useCdn: false,
      perspective: "drafts",
    });
  }
  return base;
}

export async function sanityFetchList<T>({
  query,
  params,
  tags,
  preview = false,
}: FetchArgs): Promise<T[]> {
  if (!isConfigured) return [] as T[];
  const client = resolveClient(preview);
  const result = await client.fetch<T[]>(
    query,
    params ?? {},
    preview && readToken
      ? { cache: "no-store" }
      : { next: { tags, revalidate: 3600 } },
  );
  return result ?? ([] as T[]);
}

export async function sanityFetchOne<T>({
  query,
  params,
  tags,
  preview = false,
}: FetchArgs): Promise<T | null> {
  if (!isConfigured) return null;
  const client = resolveClient(preview);
  const result = await client.fetch<T | null>(
    query,
    params ?? {},
    preview && readToken
      ? { cache: "no-store" }
      : { next: { tags, revalidate: 3600 } },
  );
  return result ?? null;
}
