import path from "path"
import { backupFile, copySkillDir, ensureDir, writeText } from "../utils/files"
import type { CodexBundle } from "../types/codex"
import type { ClaudeMcpServer } from "../types/claude"
import { transformContentForCodex } from "../utils/codex-content"

export async function writeCodexBundle(outputRoot: string, bundle: CodexBundle): Promise<void> {
  const codexRoot = resolveCodexRoot(outputRoot)
  await ensureDir(codexRoot)

  if (bundle.prompts.length > 0) {
    const promptsDir = path.join(codexRoot, "prompts")
    for (const prompt of bundle.prompts) {
      await writeText(path.join(promptsDir, `${prompt.name}.md`), prompt.content + "\n")
    }
  }

  if (bundle.skillDirs.length > 0) {
    const skillsRoot = path.join(codexRoot, "skills")
    for (const skill of bundle.skillDirs) {
      await copySkillDir(
        skill.sourceDir,
        path.join(skillsRoot, skill.name),
        (content) => transformContentForCodex(content, bundle.invocationTargets, {
          unknownSlashBehavior: "preserve",
        }),
      )
    }
  }

  if (bundle.generatedSkills.length > 0) {
    const skillsRoot = path.join(codexRoot, "skills")
    for (const skill of bundle.generatedSkills) {
      await writeText(path.join(skillsRoot, skill.name, "SKILL.md"), skill.content + "\n")
    }
  }

  const config = renderCodexConfig(bundle.mcpServers)
  if (config) {
    const configPath = path.join(codexRoot, "config.toml")
    const backupPath = await backupFile(configPath)
    if (backupPath) {
      console.log(`Backed up existing config to ${backupPath}`)
    }
    await writeText(configPath, config)
  }
}

function resolveCodexRoot(outputRoot: string): string {
  return path.basename(outputRoot) === ".codex" ? outputRoot : path.join(outputRoot, ".codex")
}

export function renderCodexConfig(mcpServers?: Record<string, ClaudeMcpServer>): string | null {
  if (!mcpServers || Object.keys(mcpServers).length === 0) return null

  const lines: string[] = ["# Generated by compound-plugin", ""]

  for (const [name, server] of Object.entries(mcpServers)) {
    const key = formatTomlKey(name)
    lines.push(`[mcp_servers.${key}]`)

    if (server.command) {
      lines.push(`command = ${formatTomlString(server.command)}`)
      if (server.args && server.args.length > 0) {
        const args = server.args.map((arg) => formatTomlString(arg)).join(", ")
        lines.push(`args = [${args}]`)
      }

      if (server.env && Object.keys(server.env).length > 0) {
        lines.push("")
        lines.push(`[mcp_servers.${key}.env]`)
        for (const [envKey, value] of Object.entries(server.env)) {
          lines.push(`${formatTomlKey(envKey)} = ${formatTomlString(value)}`)
        }
      }
    } else if (server.url) {
      lines.push(`url = ${formatTomlString(server.url)}`)
      if (server.headers && Object.keys(server.headers).length > 0) {
        lines.push(`http_headers = ${formatTomlInlineTable(server.headers)}`)
      }
    }

    lines.push("")
  }

  return lines.join("\n")
}

function formatTomlString(value: string): string {
  return JSON.stringify(value)
}

function formatTomlKey(value: string): string {
  if (/^[A-Za-z0-9_-]+$/.test(value)) return value
  return JSON.stringify(value)
}

function formatTomlInlineTable(entries: Record<string, string>): string {
  const parts = Object.entries(entries).map(
    ([key, value]) => `${formatTomlKey(key)} = ${formatTomlString(value)}`,
  )
  return `{ ${parts.join(", ")} }`
}
