import path from "path"
import { cmd } from "@/cli/cmd/cmd"
import { UI } from "@/cli/ui"
import {
  type Shell,
  MARKER_START,
  MARKER_END,
  safeDetectRepo,
  parse,
  detectShell,
  defaultRc,
  aliasLine,
  reloadHint,
  tildify,
  readMarkerBlock,
  applyBlock,
  findRepoFrom,
  detectRepo,
} from "./dev-setup-utils"

export { findRepoFrom, detectRepo } from "./dev-setup-utils"

const { TEXT_HIGHLIGHT: H, TEXT_NORMAL: N, TEXT_DIM: D, TEXT_SUCCESS: S, TEXT_NORMAL_BOLD: B } = UI.Style
const Style = UI.Style

export const DevSetupCommand = cmd({
  command: "dev-setup",
  describe: "install a `saeeoldev` shell alias for this checkout",
  builder: (y) =>
    y
      .option("shell", {
        type: "string",
        describe: "shell flavor (auto-detected from $SHELL)",
        choices: ["zsh", "bash", "fish", "powershell"] as const,
      })
      .option("rc", {
        type: "string",
        describe: "rc file to modify (auto-detected)",
      })
      .option("yes", {
        type: "boolean",
        alias: "y",
        describe: "skip confirmation",
        default: false,
      })
      .option("print", {
        type: "boolean",
        describe: "just print the snippet, do not modify any file",
        default: false,
      })
      .option("dry-run", {
        type: "boolean",
        describe: "show what would change without writing",
        default: false,
      }),
  handler: async (args) => {
    const repo = await safeDetectRepo()
    if (!repo) return
    const shell = args.shell ? parse(args.shell) : detectShell()
    const snippet = aliasLine(shell, repo)

    if (args.print) {
      process.stdout.write(snippet + "\n")
      return
    }

    const rc = args.rc ? path.resolve(args.rc) : defaultRc(shell)

    if (!process.stdin.isTTY && !args.yes && !args["dry-run"]) {
      const sh = Style.TEXT_HIGHLIGHT
      const n = Style.TEXT_NORMAL
      const dim = Style.TEXT_DIM
      process.stderr.write(
        [
          `${dim}# non-interactive shell detected${n}`,
          `${dim}# add this line to ${sh}${rc}${n}${dim} manually,${n}`,
          `${dim}# or re-run with ${sh}--yes${n}${dim} to apply automatically:${n}`,
          "",
          snippet,
          "",
        ].join("\n"),
      )
      return
    }

    UI.empty()
    UI.println(`  ${B}Saeeol CLI dev launcher setup${N}`)
    UI.empty()
    UI.println(`  ${D}Repo:${N}    ${repo}`)
    UI.println(`  ${D}Shell:${N}   ${shell}${args.shell ? "" : `  ${D}(detected from $SHELL)${N}`}`)
    UI.println(`  ${D}Config:${N}  ${tildify(rc)}`)
    UI.empty()

    const existing = await readMarkerBlock(rc)
    if (existing && existing.line === snippet) {
      UI.println(`  ${S}✓${N} already installed in ${tildify(rc)} — nothing to do`)
      UI.empty()
      UI.println(`  ${D}To remove: edit the file and delete the block marked${N}`)
      UI.println(`  ${D}${MARKER_START} ... ${MARKER_END}${N}`)
      return
    }

    const action = existing ? "update" : "install"
    UI.println(
      `  ${action === "install" ? "This will add" : "This will replace"} one line so ${H}saeeoldev${N} runs this checkout from any directory:`,
    )
    UI.empty()
    UI.println(`      ${snippet}`)
    UI.empty()

    if (args["dry-run"]) {
      UI.println(`  ${D}(dry run) would ${action} the block above in ${tildify(rc)}${N}`)
      return
    }

    if (!args.yes) {
      const answer = (await UI.input(`  Proceed? [Y/n] `)).toLowerCase()
      if (answer && !["y", "yes"].includes(answer)) {
        UI.println(`  ${D}cancelled${N}`)
        return
      }
    }

    const result = await applyBlock(rc, snippet)
    UI.empty()
    UI.println(`  ${S}✓${N} ${result.created ? "created" : "updated"} ${tildify(rc)}`)
    if (result.backup) UI.println(`  ${S}✓${N} backup at ${tildify(result.backup)}`)
    UI.empty()
    UI.println(`  ${D}Reload your shell to activate:${N}`)
    UI.println(`      ${H}${reloadHint(shell, rc)}${N}`)
  },
})

export const DevAliasCommand = cmd({
  command: "dev-alias [shell]",
  describe: false as const,
  builder: (y) =>
    y.positional("shell", {
      type: "string",
      choices: ["zsh", "bash", "fish", "powershell"] as const,
      default: "zsh",
    }),
  handler: async (args) => {
    const repo = await safeDetectRepo()
    if (!repo) return
    process.stdout.write(aliasLine(parse(args.shell), repo) + "\n")
  },
})
