import type { CollectionEntry } from "astro:content";
import type { StarlightUserConfig } from "@astrojs/starlight/types";
import fs from 'node:fs';
import path from 'node:path';
import matter from 'gray-matter';
import { sidebar as sidebarTemplate } from '../../../data/sidebar';

type SidebarItem = NonNullable<StarlightUserConfig["sidebar"]>[number];

function createCommandSidebarItem(command: CollectionEntry<'commands'>): SidebarItem & { originalPath: string } {
  const data = command.data;
  const sidebarItem = {
    label: data.name,
    slug: `reference/cli/commands/${data.path}`,
    originalPath: data.path,
  } as SidebarItem & { originalPath: string };

  if (data.experiment) {
    sidebarItem.badge = {
      variant: 'tip',
      text: 'exp',
    };
  }

  return sidebarItem;
}

function organizeCommandsIntoGroups(flatCommandItems: (SidebarItem & { originalPath: string })[]): SidebarItem[] {
  const commandItems: SidebarItem[] = [];
  const groupedCommands: Record<string, SidebarItem[]> = {};

  flatCommandItems.forEach((item) => {
    const parts = item.originalPath.split('/');

    if (parts.length === 1) {
      // Root-level command
      const { originalPath, ...cleanItem } = item;
      commandItems.push(cleanItem);
    } else {
      // Nested command
      const groupName = parts[0];
      if (!groupedCommands[groupName]) {
        groupedCommands[groupName] = [];
        commandItems.push({
          label: groupName,
          collapsed: true,
          translations: {},
          items: groupedCommands[groupName]
        });
      }
      const { originalPath, ...cleanItem } = item;
      groupedCommands[groupName].push(cleanItem);
    }
  });

  return commandItems;
}

function insertCommandsIntoSidebar(
  sidebar: SidebarItem[],
  commandItems: SidebarItem[]
): void {
  const referenceSection = sidebar.find(item =>
    typeof item === 'object' && 'label' in item && item.label === 'Reference'
  ) as { items: SidebarItem[] };

  if (!referenceSection?.items) return;

  const cliSection = referenceSection.items.find(item =>
    typeof item === 'object' && 'label' in item && item.label === 'CLI'
  ) as { items: SidebarItem[] };

  if (!cliSection?.items) return;

  // Remove existing Commands section
  cliSection.items = cliSection.items.filter(item =>
    !(typeof item === 'object' && 'label' in item && item.label === 'Commands')
  );

  // Insert new Commands section after Overview
  const overviewIndex = cliSection.items.findIndex(item =>
    typeof item === 'object' && 'label' in item && item.label === 'Overview'
  );

  if (overviewIndex !== -1) {
    cliSection.items.splice(overviewIndex + 1, 0, {
      label: 'Commands',
      collapsed: true,
      translations: {},
      items: commandItems
    });
  }
}

function expandAutogenerateDirectory(directory: string): SidebarItem[] {
  const dirPath = path.join(process.cwd(), 'src/content/docs', directory);
  if (!fs.existsSync(dirPath)) return [];

  return fs.readdirSync(dirPath)
    .filter(file => file.endsWith('.mdx') || file.endsWith('.md'))
    .map(file => {
      const content = fs.readFileSync(path.join(dirPath, file), 'utf-8');
      const { data } = matter(content);
      return {
        label: data.title as string,
        translations: {},
        slug: data.slug as string,
        attrs: {}
      };
    });
}

// Starlight v0.39+ models `autogenerate` as a standalone `{ autogenerate }` wrapper nested inside a
// group's `items`; expanding it in place would leave an extra unlabeled group.
function populateAutogeneratedSections(items: SidebarItem[]): SidebarItem[] {
  return items.flatMap((item) => {
    if (typeof item === 'object' && 'autogenerate' in item) {
      return expandAutogenerateDirectory(item.autogenerate.directory);
    }

    if (typeof item === 'object' && 'items' in item && Array.isArray(item.items)) {
      item.items = populateAutogeneratedSections(item.items);
    }

    return [item];
  });
}

export async function getSidebar(commands: CollectionEntry<'commands'>[]): Promise<SidebarItem[]> {
  // Deep clone the sidebar template to avoid mutations
  const sidebar = JSON.parse(JSON.stringify(sidebarTemplate));

  // Create flat list of command items
  const flatCommandItems = commands
    .sort((a, b) => a.data.sidebar.order - b.data.sidebar.order)
    .map(createCommandSidebarItem);

  // Organize commands into nested groups
  const commandItems = organizeCommandsIntoGroups(flatCommandItems);

  // Insert commands into the sidebar
  insertCommandsIntoSidebar(sidebar, commandItems);

  // Handle autogenerated sections
  return populateAutogeneratedSections(sidebar);
}
