import { getCollection } from 'astro:content';
import type {
  ContentType,
  Resolvable,
  CollectionPool,
  ResolvedEntry,
  BreadcrumbSegment,
  PaletteEntry,
} from '@/lib/types/content';

/** Registry
Maps each collection to the collection its `parent` field points to. Single source of truth for parent chain resolution.
**/
const PARENT_COLLECTION: Record<string, string> = {
  articles: 'articles',
  elements: 'articles',
};

const toResolvable = (
  entries: { id: string; data: { title: string; parent?: string | null } }[],
): Resolvable[] =>
  entries.map((e) => ({
    slug: e.id,
    title: e.data.title,
    parent: e.data.parent ?? null,
  }));

/** Path Building — collection-aware **/

const buildPath = (
  slug: string,
  parentSlug: string | null,
  parentCollection: string,
  pools: CollectionPool,
  visited: Set<string> = new Set(),
): string => {
  if (!parentSlug) return slug;

  const key = `${parentCollection}:${parentSlug}`;
  if (visited.has(key)) {
    console.warn(`Circular reference detected at ${key}`);
    return slug;
  }
  visited.add(key);

  const pool = pools[parentCollection];
  if (!pool) return slug;

  const parent = pool.find((e) => e.slug === parentSlug);
  if (!parent) return slug;

  const grandparentCollection =
    PARENT_COLLECTION[parentCollection] ?? parentCollection;

  const parentPath = buildPath(
    parent.slug,
    parent.parent,
    grandparentCollection,
    pools,
    visited,
  );

  return `${parentPath}/${slug}`;
};

/* Breadcrumbs
Same parent-chain walk as buildPath, but collects
{ label, href } segments. Excludes the current entry.
*/
const buildBreadcrumbs = (
  parentSlug: string | null,
  parentCollection: string,
  pools: CollectionPool,
  visited: Set<string> = new Set(),
): BreadcrumbSegment[] => {
  if (!parentSlug) return [];

  const key = `${parentCollection}:${parentSlug}`;
  if (visited.has(key)) {
    console.warn(`Circular reference detected at ${key}`);
    return [];
  }
  visited.add(key);

  const pool = pools[parentCollection];
  if (!pool) return [];

  const parent = pool.find((e) => e.slug === parentSlug);
  if (!parent) return [];

  const grandparentCollection =
    PARENT_COLLECTION[parentCollection] ?? parentCollection;

  const ancestors = buildBreadcrumbs(
    parent.parent,
    grandparentCollection,
    pools,
    visited,
  );

  const href = `/${buildPath(
    parent.slug,
    parent.parent,
    grandparentCollection,
    pools,
  )}`;

  return [...ancestors, { label: parent.title, href }];
};

/** Pool Builder**/

export const buildPools = async (): Promise<CollectionPool> => {
  const articles = await getCollection('articles');
  const elements = await getCollection('elements');

  return {
    articles: toResolvable(articles),
    elements: toResolvable(elements),
  };
};

/* Public Breadcrumb API */

export const getBreadcrumbs = async (
  parentSlug: string | null,
  collectionName: string,
): Promise<BreadcrumbSegment[]> => {
  const pools = await buildPools();
  const parentCol = PARENT_COLLECTION[collectionName] ?? collectionName;
  return buildBreadcrumbs(parentSlug, parentCol, pools);
};

/* Collection Resolution */

const resolveCollection = (
  entries: {
    id: string;
    data: { status: string; parent?: string | null; title: string };
  }[],
  type: ContentType,
  collectionName: string,
  pools: CollectionPool,
): ResolvedEntry[] => {
  const parentCol = PARENT_COLLECTION[collectionName] ?? collectionName;

  return entries
    .filter((entry) => entry.data.status === 'published')
    .map((entry) => ({
      type,
      path: buildPath(entry.id, entry.data.parent ?? null, parentCol, pools),
      entry,
    })) as ResolvedEntry[];
};

/** Palette Index
 * Transforms resolve entries into a flat, seriallizable array for the command palette.
 * Runs at build time, output gets inlined as JSON for client-side filtering
 **/
export const buildPaletteIndex = (
  resolved: ResolvedEntry[],
  pools: CollectionPool,
): PaletteEntry[] =>
  resolved.map((r) => {
    const depth = r.path.split('/').length;
    const parentSlug =
      'parent' in r.entry.data ? (r.entry.data.parent ?? null) : null;
    const parentTitle = parentSlug
      ? (Object.values(pools)
          .flat()
          .find((e) => e.slug === parentSlug)?.title ?? null)
      : null;

    return {
      label: r.entry.data.title,
      path: `/${r.path}`,
      type: r.type === 'article' && depth <= 1 ? 'section' : r.type,
      parent: parentTitle,
      depth,
    };
  });
/* Main Resolver */

export async function resolveAllPaths(): Promise<ResolvedEntry[]> {
  const pools = await buildPools();
  const pages = await getCollection('pages');

  const resolvedPages: ResolvedEntry[] = pages.map((page) => ({
    type: 'page' as const,
    path: `static/${page.id}`,
    entry: page,
  }));

  return [
    ...resolveCollection(
      await getCollection('articles'),
      'article',
      'articles',
      pools,
    ),
    ...resolveCollection(
      await getCollection('elements'),
      'element',
      'elements',
      pools,
    ),
    ...resolvedPages,
  ];
}
