import { execFile, spawn } from "child_process";
import { mkdir, readFile, writeFile } from "fs/promises";
import { homedir } from "os";
import { dirname, join } from "path";
import { promisify } from "util";
import { select } from "@inquirer/prompts";
import { ExitPromptError } from "@inquirer/core";
import { OMK_REPO_URL } from "./version.js";
import { t } from "./i18n.js";
import { style } from "./theme.js";
const execFileAsync = promisify(execFile);
export function getStarPromptStatePath(homeDir = homedir()) {
    return join(homeDir, ".omk", "star-prompt.json");
}
export function isStarPromptEligible(options = {}) {
    const env = options.env ?? process.env;
    const argv = options.argv ?? process.argv;
    const stdin = options.stdin ?? process.stdin;
    const stdout = options.stdout ?? process.stdout;
    const setting = env.OMK_STAR_PROMPT?.trim().toLowerCase();
    if (["0", "false", "off", "no", "never"].includes(setting ?? ""))
        return false;
    if (env.CI || env.GITHUB_ACTIONS)
        return false;
    if (!stdin.isTTY || !stdout.isTTY)
        return false;
    if (!options.allowChat && (options.commandName === "chat" || options.commandName === "omk"))
        return false;
    if (options.commandName === "lsp")
        return false;
    if (argv.some((arg) => ["--help", "-h", "--version", "-V", "--json"].includes(arg)))
        return false;
    return true;
}
export async function readStarPromptState(homeDir) {
    try {
        const raw = await readFile(getStarPromptStatePath(homeDir), "utf-8");
        const parsed = JSON.parse(raw);
        if (parsed.answer === "yes" || parsed.answer === "no") {
            return parsed;
        }
        return null;
    }
    catch {
        return null;
    }
}
export async function maybeAskForGitHubStar(options) {
    const env = options.env ?? process.env;
    const force = env.OMK_STAR_PROMPT?.trim().toLowerCase() === "force";
    const repoUrl = options.repoUrl ?? OMK_REPO_URL;
    if (!isStarPromptEligible({ ...options, allowChat: options.allowChat }))
        return "skipped";
    if (!force && await readStarPromptState(options.homeDir))
        return "seen";
    try {
        const accepted = options.prompt
            ? await options.prompt(repoUrl)
            : await promptForGitHubStar(repoUrl);
        const answer = accepted ? "yes" : "no";
        let starred;
        let starError;
        if (accepted) {
            try {
                await (options.starRepo ?? starGitHubRepo)(repoUrl);
                starred = true;
            }
            catch (error) {
                starred = false;
                starError = error instanceof Error ? error.message : String(error);
                const slug = parseGitHubRepoSlug(repoUrl);
                console.error(style.gray(`GitHub star failed: ${starError}`));
                if (slug)
                    console.error(style.gray(`Visit ${style.cream(`https://github.com/${slug}`)} to star manually.`));
                await (options.openBrowser ?? openRepoInBrowser)(repoUrl);
            }
        }
        await writeStarPromptState({
            promptedAt: (options.now ?? (() => new Date()))().toISOString(),
            answer,
            version: options.version,
            repoUrl,
            action: "github-star",
            starred,
            starError,
        }, options.homeDir);
        return answer;
    }
    catch (err) {
        if (err instanceof ExitPromptError)
            return "skipped";
        return "error";
    }
}
const POST_COMMAND_WHITELIST = new Set(["doctor", "hud", "plan", "parallel", "run"]);
export async function maybeAskForGitHubStarAtChatStart(options) {
    if ((options.env ?? process.env).OMK_CHAT_COCKPIT_CHILD === "1")
        return "skipped";
    return maybeAskForGitHubStar({ ...options, allowChat: true });
}
export async function maybeAskForGitHubStarAfterCommand(options) {
    const repoUrl = options.repoUrl ?? OMK_REPO_URL;
    if (!POST_COMMAND_WHITELIST.has(options.commandName))
        return "skipped";
    if (!isStarPromptEligible(options))
        return "skipped";
    if (await readStarPromptState(options.homeDir))
        return "seen";
    try {
        const accepted = options.prompt
            ? await options.prompt(repoUrl)
            : await promptForStarAfterCommand();
        const answer = accepted ? "yes" : "no";
        let starred;
        let starError;
        if (accepted) {
            try {
                await (options.starRepo ?? starGitHubRepo)(repoUrl);
                starred = true;
            }
            catch (error) {
                starred = false;
                starError = error instanceof Error ? error.message : String(error);
                const slug = parseGitHubRepoSlug(repoUrl);
                console.error(style.gray(`GitHub star failed: ${starError}`));
                if (slug)
                    console.error(style.gray(`Visit ${style.cream(`https://github.com/${slug}`)} to star manually.`));
                await (options.openBrowser ?? openRepoInBrowser)(repoUrl);
            }
        }
        await writeStarPromptState({
            promptedAt: (options.now ?? (() => new Date()))().toISOString(),
            answer,
            version: options.version,
            repoUrl,
            action: "github-star",
            starred,
            starError,
        }, options.homeDir);
        return answer;
    }
    catch (err) {
        if (err instanceof ExitPromptError)
            return "skipped";
        return "error";
    }
}
export async function getStarPromptSummary(homeDir) {
    const state = await readStarPromptState(homeDir);
    if (!state)
        return null;
    return {
        answered: true,
        starred: state.starred,
        starError: state.starError,
    };
}
async function promptForGitHubStar(repoUrl) {
    try {
        const answer = await select({
            message: t("star.prompt", repoUrl),
            choices: [
                { name: t("star.yes"), value: "yes" },
                { name: t("star.no"), value: "no" },
            ],
            default: "no",
        });
        return answer === "yes";
    }
    catch (err) {
        if (err instanceof ExitPromptError)
            return false;
        throw err;
    }
}
async function promptForStarAfterCommand() {
    try {
        const answer = await select({
            message: t("star.promptShort"),
            choices: [
                { name: t("star.yesStarIt"), value: "yes" },
                { name: t("star.no"), value: "no" },
            ],
            default: "no",
        });
        return answer === "yes";
    }
    catch (err) {
        if (err instanceof ExitPromptError)
            return false;
        throw err;
    }
}
async function writeStarPromptState(state, homeDir) {
    const statePath = getStarPromptStatePath(homeDir);
    await mkdir(dirname(statePath), { recursive: true });
    await writeFile(statePath, JSON.stringify(state, null, 2), "utf-8");
}
export function parseGitHubRepoSlug(repoUrl) {
    const normalized = repoUrl.trim().replace(/\.git$/i, "");
    const match = normalized.match(/github\.com[:/]([^/\s]+)\/([^/\s#?]+)/i);
    if (!match)
        return null;
    return `${match[1]}/${match[2]}`;
}
export async function checkGhAuth() {
    try {
        await execFileAsync("gh", ["auth", "status"], {
            timeout: 10_000,
        });
    }
    catch {
        throw new Error("GitHub CLI not authenticated. Run `gh auth login` first.");
    }
}
export async function starGitHubRepo(repoUrl) {
    const slug = parseGitHubRepoSlug(repoUrl);
    if (!slug) {
        throw new Error(`Unsupported GitHub repo URL: ${repoUrl}`);
    }
    await checkGhAuth();
    await execFileAsync("gh", ["api", "--silent", "--method", "PUT", `/user/starred/${slug}`], {
        timeout: 10_000,
    });
}
export async function openRepoInBrowser(repoUrl, opts) {
    try {
        const isTTY = opts?.isTTY ?? process.stdout.isTTY;
        const env = opts?.env ?? process.env;
        const platform = opts?.platform ?? process.platform;
        if (!isTTY)
            return false;
        if (env.CI || env.GITHUB_ACTIONS)
            return false;
        const display = opts?.display ?? env.DISPLAY;
        let cmd;
        let args;
        if (platform === "darwin") {
            cmd = "open";
            args = [repoUrl];
        }
        else if (platform === "win32") {
            cmd = "cmd";
            args = ["/c", "start", "", repoUrl];
        }
        else if (platform === "linux" && display) {
            cmd = "xdg-open";
            args = [repoUrl];
        }
        else {
            return false;
        }
        const spawnFn = opts?.spawnFn ?? spawn;
        const child = spawnFn(cmd, args, {
            stdio: "ignore",
            detached: true,
        });
        child.unref();
        return true;
    }
    catch {
        return false;
    }
}
