import metadata from '#docs/metadata';
import type {
  CategoryMeta,
  ComponentMeta,
  DocSection,
  DocsMetadata,
  GuideSection,
  ItemMeta,
  PackageGroup,
  PackageMeta,
} from '../../modules/extractor/types';

/** A unified, normalised entry for any documented leaf, regardless of kind. */
export type DocEntry
  = | { kind: 'api'; pkg: PackageMeta; category: CategoryMeta; item: ItemMeta }
    | { kind: 'components'; pkg: PackageMeta; component: ComponentMeta }
    | { kind: 'guide'; pkg: PackageMeta; section: GuideSection }
    | { kind: 'doc'; pkg: PackageMeta; section: DocSection };

export interface SearchResult {
  pkg: PackageMeta;
  slug: string;
  name: string;
  description: string;
  /** Display kind for the badge */
  badge: string;
}

const GROUP_LABELS: Record<PackageGroup, string> = {
  core: 'Core',
  vue: 'Vue',
  configs: 'Configs',
  infra: 'Infra',
};

const GROUP_ORDER: PackageGroup[] = ['core', 'vue', 'configs', 'infra'];

/** Display order for component categories (unlisted categories sort last, A–Z). */
const COMPONENT_CATEGORY_ORDER: string[] = [
  'Forms',
  'Selection',
  'Color',
  'Overlays',
  'Menus',
  'Disclosure',
  'Navigation',
  'Display',
  'Feedback',
  'Canvas & editors',
  'Utilities',
  'Other',
];

/** A category bucket of components, for grouped rendering. */
export interface ComponentGroup {
  name: string;
  components: ComponentMeta[];
}

export function useDocs() {
  const data = metadata as unknown as DocsMetadata;

  function getPackages(): PackageMeta[] {
    return data.packages;
  }

  /** Packages grouped & ordered for sidebar / landing. */
  function getGroupedPackages(): Array<{ group: PackageGroup; label: string; packages: PackageMeta[] }> {
    return GROUP_ORDER
      .map(group => ({
        group,
        label: GROUP_LABELS[group],
        packages: data.packages.filter(p => p.group === group),
      }))
      .filter(g => g.packages.length > 0);
  }

  function getPackage(slug: string): PackageMeta | undefined {
    return data.packages.find(p => p.slug === slug);
  }

  /** Number of documented leaves in a package, whatever its kind. */
  function countEntries(pkg: PackageMeta): number {
    if (pkg.kind === 'api') return pkg.categories.reduce((s, c) => s + c.items.length, 0);
    if (pkg.kind === 'components') return pkg.components.length;
    return pkg.sections.length;
  }

  /** The hand-authored intro section for a package, if any. */
  function getIntro(pkg: PackageMeta): DocSection | undefined {
    return pkg.docs.find(s => s.isIntro);
  }

  /** Non-intro doc sections (the "Guide" list shown in the sidebar). */
  function getDocSections(pkg: PackageMeta): DocSection[] {
    return pkg.docs.filter(s => !s.isIntro);
  }

  /**
   * A `components`-kind package's components bucketed by `category`, ordered by
   * {@link COMPONENT_CATEGORY_ORDER} (unlisted categories last, A–Z), with the
   * components inside each bucket kept in their incoming (alphabetical) order.
   */
  function getComponentGroups(pkg: PackageMeta): ComponentGroup[] {
    if (pkg.kind !== 'components') return [];
    const buckets = new Map<string, ComponentMeta[]>();
    for (const c of pkg.components) {
      const cat = c.category || 'Other';
      const list = buckets.get(cat);
      if (list) list.push(c);
      else buckets.set(cat, [c]);
    }
    const rank = (name: string) => {
      const i = COMPONENT_CATEGORY_ORDER.indexOf(name);
      return i === -1 ? COMPONENT_CATEGORY_ORDER.length : i;
    };
    return [...buckets.entries()]
      .map(([name, components]) => ({ name, components }))
      .sort((a, b) => rank(a.name) - rank(b.name) || a.name.localeCompare(b.name));
  }

  /** Resolve any `/:package/:slug` route to a normalised entry. */
  function resolveEntry(packageSlug: string, slug: string): DocEntry | undefined {
    const pkg = getPackage(packageSlug);
    if (!pkg) return undefined;

    // Hand-authored doc sections take precedence over auto-generated leaves.
    const docSection = pkg.docs.find(s => !s.isIntro && s.slug === slug);
    if (docSection) return { kind: 'doc', pkg, section: docSection };

    if (pkg.kind === 'api') {
      for (const category of pkg.categories) {
        const item = category.items.find(i => i.slug === slug);
        if (item) return { kind: 'api', pkg, category, item };
      }
    }
    else if (pkg.kind === 'components') {
      const component = pkg.components.find(c => c.slug === slug);
      if (component) return { kind: 'components', pkg, component };
    }
    else {
      const section = pkg.sections.find(s => s.slug === slug);
      if (section) return { kind: 'guide', pkg, section };
    }

    return undefined;
  }

  /** The default entry to open when landing on a package, if any. */
  function firstEntrySlug(pkg: PackageMeta): string | undefined {
    if (pkg.kind === 'api') return pkg.categories[0]?.items[0]?.slug;
    if (pkg.kind === 'components') return pkg.components[0]?.slug;
    return pkg.sections[0]?.slug;
  }

  function search(query: string): SearchResult[] {
    const q = query.trim().toLowerCase();
    if (!q) return [];

    const results: SearchResult[] = [];

    for (const pkg of data.packages) {
      if (pkg.kind === 'api') {
        for (const category of pkg.categories) {
          for (const item of category.items) {
            if (item.name.toLowerCase().includes(q) || item.description.toLowerCase().includes(q)) {
              results.push({ pkg, slug: item.slug, name: item.name, description: item.description, badge: item.kind });
            }
          }
        }
      }
      else if (pkg.kind === 'components') {
        for (const c of pkg.components) {
          if (c.name.toLowerCase().includes(q) || c.description.toLowerCase().includes(q)) {
            results.push({ pkg, slug: c.slug, name: c.name, description: c.description || `${c.parts.length} parts`, badge: 'component' });
          }
        }
      }
      else {
        for (const s of pkg.sections) {
          if (s.title.toLowerCase().includes(q) || s.markdown.toLowerCase().includes(q)) {
            results.push({ pkg, slug: s.slug, name: s.title, description: pkg.name, badge: 'guide' });
          }
        }
      }
    }

    return results;
  }

  function getTotalItems(): number {
    return data.packages.reduce((sum, pkg) => sum + countEntries(pkg), 0);
  }

  return {
    data,
    getPackages,
    getGroupedPackages,
    getPackage,
    countEntries,
    resolveEntry,
    firstEntrySlug,
    getIntro,
    getDocSections,
    getComponentGroups,
    search,
    getTotalItems,
  };
}
