import React, { useState, useEffect } from "react";
import { render, Text, Box, useInput, useApp } from "ink";
import * as fs from "fs";
import * as path from "path";
import devcert from "devcert";
const SPECIFIC_INSTRUCTIONS = `Use Specific to handle all infrastructure and development environments: like deployments, databases, services, secrets, configuration and environment variables. Run \`specific docs\` to learn how to use Specific. ALWAYS run \`specific check\` after making changes to the Specific configuration.`;
const CURSOR_MDC_CONTENT = `---
description: Specific infrastructure rules
globs:
alwaysApply: true
---

${SPECIFIC_INSTRUCTIONS}
`;
const options = [
    { id: "cursor", label: "Cursor" },
    { id: "claude", label: "Claude Code" },
    { id: "codex", label: "Codex / AGENTS.md" },
];
function isGitProject() {
    const gitPath = path.join(process.cwd(), ".git");
    return fs.existsSync(gitPath);
}
function detectExistingAgents() {
    const detected = {};
    // Detect Cursor: check if .cursor exists
    const cursorDir = path.join(process.cwd(), ".cursor");
    if (fs.existsSync(cursorDir)) {
        detected["cursor"] = true;
    }
    // Detect Claude Code: check if .claude or CLAUDE.md exists
    const claudeDir = path.join(process.cwd(), ".claude");
    const claudeMd = path.join(process.cwd(), "CLAUDE.md");
    if (fs.existsSync(claudeDir) || fs.existsSync(claudeMd)) {
        detected["claude"] = true;
    }
    // Detect Codex: check if AGENTS.md exists
    const agentsMd = path.join(process.cwd(), "AGENTS.md");
    if (fs.existsSync(agentsMd)) {
        detected["codex"] = true;
    }
    return detected;
}
function appendOrCreateFile(filePath, content) {
    if (fs.existsSync(filePath)) {
        const existing = fs.readFileSync(filePath, "utf-8");
        if (existing.includes("specific docs") || existing.includes("specific check")) {
            return "unchanged";
        }
        const separator = existing.endsWith("\n") ? "\n" : "\n\n";
        fs.writeFileSync(filePath, existing + separator + content + "\n");
        return "modified";
    }
    else {
        fs.writeFileSync(filePath, content + "\n");
        return "created";
    }
}
function addToGitignore() {
    const gitignorePath = path.join(process.cwd(), ".gitignore");
    const entries = [".specific", "specific.secrets"];
    if (fs.existsSync(gitignorePath)) {
        const existing = fs.readFileSync(gitignorePath, "utf-8");
        const lines = existing.split("\n").map((l) => l.trim());
        const missingEntries = entries.filter((entry) => !lines.includes(entry));
        if (missingEntries.length === 0) {
            return "unchanged";
        }
        const separator = existing.endsWith("\n") ? "" : "\n";
        fs.writeFileSync(gitignorePath, existing + separator + missingEntries.join("\n") + "\n");
        return "modified";
    }
    else {
        fs.writeFileSync(gitignorePath, entries.join("\n") + "\n");
        return "created";
    }
}
function configureClaudeCodePermissions() {
    const claudeDir = path.join(process.cwd(), ".claude");
    const settingsPath = path.join(claudeDir, "settings.local.json");
    const permissions = ["Bash(specific docs:*)", "Bash(specific check:*)"];
    if (fs.existsSync(settingsPath)) {
        const existing = JSON.parse(fs.readFileSync(settingsPath, "utf-8"));
        const allowList = existing?.permissions?.allow || [];
        const missingPermissions = permissions.filter((p) => !allowList.includes(p));
        if (missingPermissions.length === 0) {
            return "unchanged";
        }
        if (!existing.permissions) {
            existing.permissions = {};
        }
        if (!existing.permissions.allow) {
            existing.permissions.allow = [];
        }
        existing.permissions.allow.push(...missingPermissions);
        fs.writeFileSync(settingsPath, JSON.stringify(existing, null, 2) + "\n");
        return "modified";
    }
    if (!fs.existsSync(claudeDir)) {
        fs.mkdirSync(claudeDir);
    }
    const settings = {
        permissions: {
            allow: permissions,
        },
    };
    fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
    return "created";
}
function createCursorRule() {
    const cursorDir = path.join(process.cwd(), ".cursor");
    const rulesDir = path.join(cursorDir, "rules");
    const mdcPath = path.join(rulesDir, "specific.mdc");
    if (fs.existsSync(mdcPath)) {
        const existing = fs.readFileSync(mdcPath, "utf-8");
        if (existing.includes("specific docs") || existing.includes("specific check")) {
            return "unchanged";
        }
        fs.writeFileSync(mdcPath, CURSOR_MDC_CONTENT);
        return "modified";
    }
    if (!fs.existsSync(cursorDir)) {
        fs.mkdirSync(cursorDir);
    }
    if (!fs.existsSync(rulesDir)) {
        fs.mkdirSync(rulesDir);
    }
    fs.writeFileSync(mdcPath, CURSOR_MDC_CONTENT);
    return "created";
}
function configureAgents(checked) {
    const agents = {
        filesCreated: [],
        filesModified: [],
    };
    if (checked["cursor"]) {
        const status = createCursorRule();
        if (status === "created")
            agents.filesCreated.push(".cursor/rules/specific.mdc");
        else if (status === "modified")
            agents.filesModified.push(".cursor/rules/specific.mdc");
    }
    if (checked["claude"]) {
        const claudeMdPath = path.join(process.cwd(), "CLAUDE.md");
        const status = appendOrCreateFile(claudeMdPath, SPECIFIC_INSTRUCTIONS);
        if (status === "created")
            agents.filesCreated.push("CLAUDE.md");
        else if (status === "modified")
            agents.filesModified.push("CLAUDE.md");
        const permStatus = configureClaudeCodePermissions();
        if (permStatus === "created")
            agents.filesCreated.push(".claude/settings.local.json");
        else if (permStatus === "modified")
            agents.filesModified.push(".claude/settings.local.json");
    }
    if (checked["codex"]) {
        const agentsMdPath = path.join(process.cwd(), "AGENTS.md");
        const status = appendOrCreateFile(agentsMdPath, SPECIFIC_INSTRUCTIONS);
        if (status === "created")
            agents.filesCreated.push("AGENTS.md");
        else if (status === "modified")
            agents.filesModified.push("AGENTS.md");
    }
    let git = null;
    if (isGitProject()) {
        git = { filesCreated: [], filesModified: [] };
        const status = addToGitignore();
        if (status === "created")
            git.filesCreated.push(".gitignore");
        else if (status === "modified")
            git.filesModified.push(".gitignore");
    }
    return { agents, git };
}
function InitUI() {
    const { exit } = useApp();
    const [initialState] = useState(() => {
        const detected = detectExistingAgents();
        const hasDetected = Object.keys(detected).length > 0;
        return {
            detected,
            focusedIndex: hasDetected ? options.length : 0, // Focus submit if any detected
        };
    });
    const [phase, setPhase] = useState("tls");
    const [focusedIndex, setFocusedIndex] = useState(initialState.focusedIndex);
    const [checked, setChecked] = useState(initialState.detected);
    const [result, setResult] = useState(null);
    const [tlsResult, setTlsResult] = useState(null);
    // Run TLS installation on mount
    useEffect(() => {
        let cancelled = false;
        async function installTls() {
            try {
                await devcert.certificateFor("localhost");
                if (!cancelled) {
                    setTlsResult({ status: "success" });
                    setPhase("agents");
                }
            }
            catch (err) {
                if (!cancelled) {
                    setTlsResult({
                        status: "error",
                        error: err instanceof Error ? err.message : String(err)
                    });
                    setPhase("agents");
                }
            }
        }
        installTls();
        return () => { cancelled = true; };
    }, []);
    const isSubmitFocused = focusedIndex === options.length;
    useInput((input, key) => {
        if (phase !== "agents")
            return;
        if (key.upArrow || input === "k") {
            setFocusedIndex((prev) => Math.max(0, prev - 1));
        }
        else if (key.downArrow || input === "j") {
            setFocusedIndex((prev) => Math.min(options.length, prev + 1));
        }
        else if (input === " " && !isSubmitFocused) {
            const option = options[focusedIndex];
            setChecked((prev) => ({
                ...prev,
                [option.id]: !prev[option.id],
            }));
        }
        else if ((key.return || input === " ") && isSubmitFocused) {
            const configResult = configureAgents(checked);
            setResult(configResult);
            setPhase("done");
        }
    });
    useEffect(() => {
        if (phase === "done") {
            const timer = setTimeout(() => {
                exit();
            }, 100);
            return () => clearTimeout(timer);
        }
    }, [phase, exit]);
    // TLS phase - show only TLS installation status
    if (phase === "tls") {
        return (React.createElement(Box, { flexDirection: "column" },
            React.createElement(Text, null,
                React.createElement(Text, { dimColor: true }, "\u25CF"),
                " Installing TLS certificates... ",
                React.createElement(Text, { dimColor: true }, "(may require your password)"))));
    }
    // Done phase - show summary
    if (phase === "done") {
        const selectedAgents = Object.entries(checked).filter(([, v]) => v).length;
        const agentChanges = result && (result.agents.filesCreated.length > 0 || result.agents.filesModified.length > 0);
        const gitChanges = result?.git && (result.git.filesCreated.length > 0 || result.git.filesModified.length > 0);
        return (React.createElement(Box, { flexDirection: "column" },
            tlsResult === null && (React.createElement(Text, null,
                React.createElement(Text, { dimColor: true }, "\u25CF"),
                " Installing TLS certificates...")),
            tlsResult?.status === "success" && (React.createElement(Text, null,
                React.createElement(Text, { color: "green" }, "\u2713"),
                " TLS certificates installed")),
            tlsResult?.status === "error" && (React.createElement(React.Fragment, null,
                React.createElement(Text, null,
                    React.createElement(Text, { color: "red" }, "\u2717"),
                    " Failed to install TLS certificates"),
                React.createElement(Text, { dimColor: true },
                    "  ",
                    tlsResult.error))),
            result && (React.createElement(React.Fragment, null,
                React.createElement(Text, null,
                    React.createElement(Text, { color: "green" }, "\u2713"),
                    " Coding agents configured"),
                result.agents.filesCreated.length > 0 && (React.createElement(Text, { dimColor: true },
                    "  Created: ",
                    result.agents.filesCreated.join(", "))),
                result.agents.filesModified.length > 0 && (React.createElement(Text, { dimColor: true },
                    "  Modified: ",
                    result.agents.filesModified.join(", "))),
                !agentChanges && selectedAgents > 0 && (React.createElement(Text, { dimColor: true }, "  No changes needed (files already configured)")),
                selectedAgents === 0 && (React.createElement(Text, { dimColor: true }, "  No agents selected")))),
            result?.git && (React.createElement(React.Fragment, null,
                React.createElement(Text, null,
                    React.createElement(Text, { color: "green" }, "\u2713"),
                    " Git configured"),
                result.git.filesCreated.length > 0 && (React.createElement(Text, { dimColor: true },
                    "  Created: ",
                    result.git.filesCreated.join(", "))),
                result.git.filesModified.length > 0 && (React.createElement(Text, { dimColor: true },
                    "  Modified: ",
                    result.git.filesModified.join(", "))),
                !gitChanges && (React.createElement(Text, { dimColor: true }, "  No changes needed (.gitignore already configured)"))))));
    }
    // Agents selection phase
    const tlsLine = tlsResult === null
        ? React.createElement(Text, null,
            React.createElement(Text, { dimColor: true }, "\u25CF"),
            " Installing TLS certificates... ",
            React.createElement(Text, { dimColor: true }, "(may require your password)"))
        : tlsResult.status === "success"
            ? React.createElement(Text, null,
                React.createElement(Text, { color: "green" }, "\u2713"),
                " TLS certificates installed")
            : React.createElement(Text, null,
                React.createElement(Text, { color: "red" }, "\u2717"),
                " TLS certificates failed ",
                React.createElement(Text, { dimColor: true },
                    "(",
                    tlsResult.error,
                    ")"));
    return (React.createElement(Box, { flexDirection: "column" },
        tlsLine,
        React.createElement(Text, null,
            React.createElement(Text, { dimColor: true }, "\u25CF"),
            " Configure coding agents ",
            React.createElement(Text, { dimColor: true }, "(space to select)")),
        React.createElement(Text, null, " "),
        options.map((option, index) => {
            const isFocused = focusedIndex === index;
            const isChecked = checked[option.id];
            return (React.createElement(Box, { key: option.id },
                React.createElement(Text, { ...(isFocused && { color: "cyan" }) },
                    isFocused ? "❯ " : "  ",
                    isChecked ? "[✓]" : "[ ]",
                    " ",
                    option.label)));
        }),
        React.createElement(Text, null, " "),
        React.createElement(Box, null,
            React.createElement(Text, { ...(isSubmitFocused && { color: "cyan" }) },
                isSubmitFocused ? "❯ " : "  ",
                React.createElement(Text, { inverse: isSubmitFocused, ...(!isSubmitFocused && { backgroundColor: "gray" }) }, " Continue ")))));
}
export function initCommand() {
    render(React.createElement(InitUI, null));
}
//# sourceMappingURL=init.js.map