import { fetchGraphQL } from "../client";
import { SEO_FIELDS, IMAGE_FIELDS } from "../fragments";
import type { WpSeo, WpImageField } from "../types";

export interface WpBibSource {
  reference: string | null;
  url: string | null;
}

export interface WpPost {
  slug: string;
  title: string | null;
  date: string | null;
  modified: string | null;
  content: string | null;
  excerpt: string | null;
  featuredImage?: WpImageField | null;
  author?: { node?: { name?: string | null } | null } | null;
  categories?: { nodes?: { name: string; slug: string }[] | null } | null;
  seo?: WpSeo | null;
  article?: {
    enBref?: { point: string | null }[] | null;
    bibliographie?: WpBibSource[] | null;
  } | null;
}

export interface WpPostCard {
  slug: string;
  title: string | null;
  date: string | null;
  excerpt: string | null;
  featuredImage?: WpImageField | null;
  categories?: { nodes?: { name: string; slug: string }[] | null } | null;
}

const POST_FIELDS = /* GraphQL */ `
  slug
  title
  date
  modified
  content
  excerpt
  featuredImage ${IMAGE_FIELDS}
  author { node { name } }
  categories { nodes { name slug } }
  seo ${SEO_FIELDS}
  article {
    enBref { point }
    bibliographie { reference url }
  }
`;

const CARD_FIELDS = /* GraphQL */ `
  slug
  title
  date
  excerpt
  featuredImage ${IMAGE_FIELDS}
  categories { nodes { name slug } }
`;

const POST_QUERY = /* GraphQL */ `
  query GetPost($slug: ID!) {
    post(id: $slug, idType: SLUG) { ${POST_FIELDS} }
  }
`;

/** Article de blog par slug. */
export async function getWpPost(slug: string): Promise<WpPost | null> {
  const data = await fetchGraphQL<{ post: WpPost | null }>(
    POST_QUERY,
    { slug },
    { tags: ["post", `post:${slug}`] }
  );
  return data.post ?? null;
}

const SLUGS_QUERY = /* GraphQL */ `
  query GetPostSlugs($after: String) {
    posts(first: 100, after: $after, where: { status: PUBLISH }) {
      pageInfo { hasNextPage endCursor }
      nodes { slug }
    }
  }
`;

/** Tous les slugs d'articles publiés (pagination par curseur). */
export async function getAllPostSlugs(): Promise<string[]> {
  const slugs: string[] = [];
  let after: string | null = null;
  let hasNextPage = true;
  while (hasNextPage) {
    const data: {
      posts: {
        pageInfo: { hasNextPage: boolean; endCursor: string | null };
        nodes: { slug: string }[] | null;
      } | null;
    } = await fetchGraphQL(SLUGS_QUERY, { after }, { tags: ["post", "listing:posts"] });
    for (const n of data.posts?.nodes ?? []) if (n.slug) slugs.push(n.slug);
    hasNextPage = Boolean(data.posts?.pageInfo?.hasNextPage);
    after = data.posts?.pageInfo?.endCursor ?? null;
  }
  return slugs;
}

const POSTS_QUERY = /* GraphQL */ `
  query GetPosts($after: String) {
    posts(first: 100, after: $after, where: { status: PUBLISH, orderby: [{ field: DATE, order: DESC }] }) {
      pageInfo { hasNextPage endCursor }
      nodes { ${CARD_FIELDS} }
    }
  }
`;

/** Tous les articles (cards) pour la liste /blog, triés par date desc. */
export async function getAllPosts(): Promise<WpPostCard[]> {
  const cards: WpPostCard[] = [];
  let after: string | null = null;
  let hasNextPage = true;
  while (hasNextPage) {
    const data: {
      posts: {
        pageInfo: { hasNextPage: boolean; endCursor: string | null };
        nodes: WpPostCard[] | null;
      } | null;
    } = await fetchGraphQL(POSTS_QUERY, { after }, { tags: ["post", "listing:posts"] });
    for (const n of data.posts?.nodes ?? []) cards.push(n);
    hasNextPage = Boolean(data.posts?.pageInfo?.hasNextPage);
    after = data.posts?.pageInfo?.endCursor ?? null;
  }
  return cards;
}

const LATEST_QUERY = /* GraphQL */ `
  query GetLatestPosts($first: Int!) {
    posts(first: $first, where: { status: PUBLISH, orderby: [{ field: DATE, order: DESC }] }) {
      nodes { ${CARD_FIELDS} }
    }
  }
`;

/** N derniers articles (section blog de la home). */
export async function getLatestPosts(first = 3): Promise<WpPostCard[]> {
  const data = await fetchGraphQL<{ posts: { nodes: WpPostCard[] | null } | null }>(
    LATEST_QUERY,
    { first },
    { tags: ["post", "listing:posts"] }
  );
  return data.posts?.nodes ?? [];
}

const RELATED_QUERY = /* GraphQL */ `
  query GetRelated($category: String!, $first: Int!) {
    posts(first: $first, where: { status: PUBLISH, categoryName: $category, orderby: [{ field: DATE, order: DESC }] }) {
      nodes { ${CARD_FIELDS} }
    }
  }
`;

/** Articles de la même catégorie (hors article courant). */
export async function getRelatedPosts(
  category: string,
  excludeSlug: string,
  first = 3
): Promise<WpPostCard[]> {
  if (!category) return [];
  const data = await fetchGraphQL<{ posts: { nodes: WpPostCard[] | null } | null }>(
    RELATED_QUERY,
    { category, first: first + 1 },
    { tags: ["post", "listing:posts"] }
  );
  return (data.posts?.nodes ?? []).filter((p) => p.slug !== excludeSlug).slice(0, first);
}
