import fs from 'node:fs'
import path from 'node:path'
import process from 'node:process'
import { consola, fromRoot } from '@hugo-fixit/shared'
import { Command } from 'commander'
import c from 'picocolors'
import { applyTemplate, generateDocs } from './parsers/config-parser'
import { parsePartials } from './parsers/partial-parser'
import { renderConfigStandalone } from './renderers/config'
import { generatePartialsDocs } from './renderers/partials'

function writeFile(filePath: string, content: string): void {
  fs.writeFileSync(filePath, content, 'utf-8')
  consola.success(`Written ${c.cyan(filePath)}`)
}

// ─── Partials helpers ───

const PARTIALS_START = '<!-- HUGO_FIXIT_PARTIALS:START -->'
const PARTIALS_END = '<!-- HUGO_FIXIT_PARTIALS:END -->'

function applyPartialsTemplate(body: string, templatePath: string, outputPath?: string, command?: string): void {
  const template = fs.readFileSync(templatePath, 'utf-8')
  const startIdx = template.indexOf(PARTIALS_START)
  const endIdx = template.indexOf(PARTIALS_END)

  if (startIdx === -1 || endIdx === -1) {
    throw new Error(`Markers not found in template file. Expected both "${PARTIALS_START}" and "${PARTIALS_END}".`)
  }
  if (startIdx > endIdx) {
    throw new Error('START marker appears after END marker in template file.')
  }

  const before = template.slice(0, startIdx + PARTIALS_START.length)
  const after = template.slice(endIdx)
  const comment = command
    ? `<!--\nAutomatically generated by the \`${command}\` command.\nDo not modify it manually!\n-->\n\n`
    : ''
  const result = `${before}\n${comment}${body}\n${after}`

  const dest = outputPath || templatePath
  fs.writeFileSync(dest, result, 'utf-8')
}

function generatePartialsAction(options: { output?: string, template?: string }): void {
  const groups = parsePartials()
  const body = generatePartialsDocs(groups)

  if (options.template) {
    const templatePath = path.resolve(process.cwd(), options.template)
    if (!fs.existsSync(templatePath)) {
      consola.error(`Template not found: ${templatePath}`)
      process.exit(1)
    }
    const outputPath = options.output ? path.resolve(process.cwd(), options.output) : undefined
    let cmd = `pnpm gen:docs partials -t ${options.template}`
    if (options.output)
      cmd += ` -o ${options.output}`
    applyPartialsTemplate(body, templatePath, outputPath, cmd)
    const dest = outputPath || templatePath
    consola.success(`Partials docs applied: ${c.cyan(dest)}`)
    return
  }

  if (options.output) {
    const outPath = path.resolve(process.cwd(), options.output)
    fs.writeFileSync(outPath, body, 'utf-8')
    consola.success(`Written ${c.cyan(outPath)}`)
    return
  }

  // Default: inject into en docs template
  const templatePath = fromRoot('../fixit-docs/content/en/references/partials/index.md')
  applyPartialsTemplate(body, templatePath, undefined, 'pnpm gen:docs')
}

// ─── Subcommands ───

async function configAction(
  file: string,
  options: { output?: string, template?: string },
): Promise<void> {
  let source = file
  let content: string

  if (source === 'latest') {
    consola.start('Resolving latest FixIt release version...')
    try {
      const res = await fetch('https://api.github.com/repos/hugo-fixit/FixIt/releases/latest', {
        headers: {
          'User-Agent': 'gen-docs',
          ...(process.env.GITHUB_TOKEN && { Authorization: `Bearer ${process.env.GITHUB_TOKEN}` }),
        },
      })
      if (!res.ok)
        throw new Error(`HTTP ${res.status}`)
      const { tag_name: version } = await res.json() as { tag_name: string }
      source = `https://raw.githubusercontent.com/hugo-fixit/FixIt/refs/tags/${version}/hugo.toml`
      consola.success(`Resolved latest release: ${c.cyan(version)}`)
    }
    catch (error) {
      consola.error(`Failed to resolve latest release: ${(error as Error).message}`)
      process.exit(1)
    }
  }

  if (/^https?:\/\//i.test(source)) {
    consola.start(`Downloading from: ${c.cyan(source)}`)
    try {
      const res = await fetch(source)
      if (!res.ok)
        throw new Error(`HTTP ${res.status}`)
      content = await res.text()
      consola.success('Remote file downloaded.')
    }
    catch (error) {
      consola.error(`Failed to download: ${(error as Error).message}`)
      process.exit(1)
    }
  }
  else {
    const inputPath = source === 'hugo.toml' ? fromRoot('hugo.toml') : path.resolve(process.cwd(), source)
    if (!fs.existsSync(inputPath)) {
      consola.error(`File not found: ${inputPath}`)
      process.exit(1)
    }
    content = fs.readFileSync(inputPath, 'utf-8')
  }

  if (options.template) {
    const templatePath = path.resolve(process.cwd(), options.template)
    if (!fs.existsSync(templatePath)) {
      consola.error(`Template file not found: ${templatePath}`)
      process.exit(1)
    }
    const outputPath = options.output ? path.resolve(process.cwd(), options.output) : undefined
    let cmd = `gen-docs config ${file}`
    if (options.template)
      cmd += ` -t ${options.template}`
    if (options.output)
      cmd += ` -o ${options.output}`
    applyTemplate(content, templatePath, outputPath, cmd)
    const dest = outputPath || templatePath
    consola.success(`Documentation applied to template: ${c.cyan(dest)}`)
    return
  }

  const body = generateDocs(content)
  if (options.output) {
    const outPath = path.resolve(process.cwd(), options.output)
    writeFile(outPath, renderConfigStandalone(body))
  }
  else {
    process.stdout.write(`${body}\n`)
  }
}

function allAction(): void {
  // Config API — inject into docs params page
  consola.start('Parsing hugo.toml...')
  const tomlContent = fs.readFileSync(fromRoot('hugo.toml'), 'utf-8')
  const templatePath = fromRoot('../fixit-docs/content/en/documentation/getting-started/configuration/params/index.md')
  applyTemplate(tomlContent, templatePath, undefined, 'pnpm gen:docs')
  consola.success('Config docs generated!')

  // Partials API — inject into en docs partials page
  consola.start('Generating Hugo partials docs...')
  generatePartialsAction({})
  consola.success('Partials docs generated!')
}

// ─── CLI ───

const program = new Command()

program
  .name('gen-docs')
  .description('Generate API reference documentation for the FixIt Hugo theme')

program
  .command('config')
  .description('Generate configuration reference from hugo.toml')
  .argument('[file]', 'Input hugo.toml path, URL, or "latest"', 'hugo.toml')
  .option('-o, --output <file>', 'Output file path (default: stdout)')
  .option('-t, --template <file>', 'Template file with HUGO_FIXIT_PARAMS markers to inject docs into')
  .action(configAction)

program
  .command('partials')
  .description('Generate Hugo partials reference from layouts/_partials/')
  .option('-o, --output <file>', 'Output file path (default: stdout)')
  .option('-t, --template <file>', 'Template file with HUGO_FIXIT_PARTIALS markers to inject docs into')
  .action(generatePartialsAction)

// Default action (no subcommand): inject config + partials docs into docs pages
program
  .action(() => allAction())

program.parse()
