// Client GraphQL minimal pour WPGraphQL (fetch natif, cache Next taggué).

const WP_GRAPHQL_URL = process.env.WORDPRESS_GRAPHQL_URL;

/** Indique si le backend WordPress est configuré (sinon le front utilisera ses fallbacks). */
export const isWpConfigured = () => Boolean(process.env.WORDPRESS_GRAPHQL_URL);

// ── Limiteur de concurrence ──────────────────────────────────────────────────
// Le build statique génère des centaines de pages (lieux + CPT + i18n) en
// parallèle : sans plafond, on sature les connexions MariaDB du WP headless
// ("Too many connections" → HTTP 500). On borne donc le nombre de requêtes
// GraphQL simultanées (réglable via WP_FETCH_CONCURRENCY).
const MAX_CONCURRENT = Math.max(1, Number(process.env.WP_FETCH_CONCURRENCY) || 8);
let active = 0;
const waiters: Array<() => void> = [];

function acquire(): Promise<void> {
  if (active < MAX_CONCURRENT) {
    active++;
    return Promise.resolve();
  }
  return new Promise<void>((resolve) => waiters.push(resolve));
}

function release(): void {
  const next = waiters.shift();
  if (next) {
    next(); // on cède la place : `active` reste constant
  } else {
    active--;
  }
}

interface GraphQLError {
  message: string;
  locations?: { line: number; column: number }[];
  path?: (string | number)[];
}

interface GraphQLResponse<T> {
  data?: T;
  errors?: GraphQLError[];
}

/**
 * POST une query GraphQL vers WordPress.
 * Cache : `revalidate: false` + tags — invalidation uniquement via /api/revalidate.
 */
export async function fetchGraphQL<T>(
  query: string,
  variables?: Record<string, unknown>,
  opts?: { tags?: string[] }
): Promise<T> {
  if (!WP_GRAPHQL_URL) {
    throw new Error(
      "WORDPRESS_GRAPHQL_URL manquant : définis la variable d'environnement (ex. https://covalba-admin.paf-studio.dev/graphql) avant d'appeler fetchGraphQL."
    );
  }

  await acquire();
  try {
    const res = await fetch(WP_GRAPHQL_URL, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ query, variables }),
      next: {
        revalidate: false as const,
        tags: ["wordpress", ...(opts?.tags ?? [])],
      },
    });

    if (!res.ok) {
      const body = await res.text().catch(() => "");
      throw new Error(
        `WPGraphQL HTTP ${res.status} ${res.statusText} sur ${WP_GRAPHQL_URL}${body ? ` — ${body.slice(0, 500)}` : ""}`
      );
    }

    const json = (await res.json()) as GraphQLResponse<T>;

    if (json.errors?.length) {
      const details = json.errors
        .map((e) => {
          const loc = e.locations?.map((l) => `${l.line}:${l.column}`).join(",");
          const path = e.path?.join(".");
          return `${e.message}${path ? ` (path: ${path})` : ""}${loc ? ` (loc: ${loc})` : ""}`;
        })
        .join(" | ");
      throw new Error(`Erreurs GraphQL WordPress : ${details}`);
    }

    if (json.data === undefined) {
      throw new Error("Réponse GraphQL WordPress sans champ data.");
    }

    return json.data;
  } finally {
    release();
  }
}
