import { relative, resolve } from 'node:path';
import { readFileSync, writeFileSync } from 'node:fs';
import { format } from 'prettier';
import consola from 'consola';
import { execaCommand } from 'execa';

let hasGenerated = false;

const cliDir = resolve('src/cli/commands');
const cliDirGlob = resolve(cliDir, '**');
const cliTemplatePath = resolve('docs/.vitepress/plugins/cli.tpl.md');
const cliPath = resolve('docs/api/cli.md');

const PREFACE = `<!--
DO NOT EDIT
Generated by \`wxt/docs/.vitepress/plugins/generate-config-docs.ts\`
To make changes to the config reference, update the JSDoc in \`src/core/types/external.ts\`.
-->`;

export function generateCliDocs() {
  writeFileSync(cliPath, '');

  const generateDocs = async () => {
    consola.info(`Generating ${relative(process.cwd(), cliPath)}`);
    try {
      const res = await execaCommand('pnpm -s wxt --help');
      const dev = splitInfo(res.stdout);
      const lines: Array<string | string[]> = [
        `## \`wxt\``,
        '```sh',
        dev.rest,
        '```',
      ];

      const commands = await Promise.all(
        extractCommands(dev.info).map(async (command) => {
          const res = await execaCommand(`pnpm -s wxt ${command} --help`);
          const { rest: docs } = splitInfo(res.stdout);
          return [`## \`wxt ${command}\``, '```sh', docs, '```'];
        }),
      );
      lines.push(...commands);

      const text = await format(
        PREFACE +
          '\n\n' +
          readFileSync(cliTemplatePath, 'utf-8').replace(
            '{{ DOCS }}',
            lines.flat().join('\n'),
          ),
        { parser: 'markdown' },
      );

      writeFileSync(cliPath, text);
      consola.success(`Generated ${relative(process.cwd(), cliPath)}`);
    } catch (err) {
      consola.fail(`Failed to generate ${relative(process.cwd(), cliPath)}`);
      consola.error(err.message);
    }
  };

  return {
    name: 'docs:generate-cli-docs',
    async config() {
      if (!hasGenerated) {
        hasGenerated = true;
        await generateDocs();
      }
    },
    configureServer(server: any) {
      server.watcher.add(cliDirGlob);
    },
    async handleHotUpdate(ctx: { file: string }) {
      if (ctx.file === cliTemplatePath || ctx.file.includes(cliDir)) {
        await generateDocs();
      }
    },
  };
}

function splitInfo(text: string): { info: string; rest: string } {
  const infoStart = text.indexOf('For more info,');
  const infoEnd = text.indexOf('\n\nOptions:');

  if (infoStart === -1 || infoEnd === -1) {
    return { info: '', rest: text };
  }

  const info = text.substring(infoStart, infoEnd).trim();
  const rest = text.replace(info, '').trim().replace('\n\n\n\n', '\n\n');

  return { info, rest };
}

function extractCommands(info: string): string[] {
  const commands: string[] = [];

  // Split the info by line and iterate through each line
  info.split('\n').forEach((line) => {
    // Use regex to capture the command after "$ wxt " and before "--help"
    const match = line.match(/\$ wxt (\w+) --help/);
    if (match && match[1]) {
      commands.push(match[1]);
    }
  });

  return commands;
}
