import crypto from "node:crypto";
import fss from "node:fs";
import path from "node:path";
import { getGlobalPatternsDir } from "../../knowledge/loader.js";
import { detectFingerprint, generateConfigDraft, validateConfigDraft, generateConfigEvidence, canAutoWrite, parseBlueprint, generateBlueprintEvidence, } from "../../engine/config/zero_config_init.js";
import YAML from "yaml";
import { debug, userInfo, userError, internalWarn } from "../../engine/core/logger.js";
import { args, getArgValue } from "../args.js";
import { cmdGenerateHooks, cmdGenerateClaudeMdInner, cmdGenerateTraeInner, cmdGenerateCodexInner, } from "./hooks.js";
import { interactiveConfig } from "./status.js";
import { atomicWriteFileSync } from "../../engine/core/write_file_atomic.js";
import { errorMessage, safeJsonParse } from "../../engine/core/helpers.js";
/**
 * 创建 .soloforge 项目目录结构 — 统一入口，消除三处重复 dirs 数组。
 *
 * 完整目录集是 cmdInit 的超集。
 * finishInitAutoConfig 和 cmdInitBlueprint 使用默认参数（不含系统专属目录）。
 */
export function createProjectDirs(projectPath, options) {
    const includeNew = options?.includeNewSystem ?? false;
    const includeExisting = options?.includeExistingSystem ?? false;
    const dirs = [
        // 状态目录
        ".soloforge/state",
        ".soloforge/state/debt",
        // 知识目录 — patterns
        ".soloforge/knowledge/patterns",
        ".soloforge/knowledge/patterns/core",
        ".soloforge/knowledge/patterns/temp",
        // 知识目录 — procedures
        ".soloforge/knowledge/procedures",
        // 知识目录 — domain
        ".soloforge/knowledge/domain/backend",
        ".soloforge/knowledge/domain/frontend",
        // 知识目录 — checklists
        ".soloforge/knowledge/checklists",
        // 知识目录 — staged
        ".soloforge/staged",
        // 以下为交互式 init 专属目录（auto/blueprint 不需要）
        ".soloforge/knowledge/internal/rules",
        ".soloforge/knowledge/internal/patterns",
        ".soloforge/knowledge/rules/shared",
        ".soloforge/knowledge/profiles",
        ".soloforge/knowledge/artifacts/shared",
        ".soloforge/templates/artifacts/shared",
        ".soloforge/templates/rules/shared",
        ".soloforge/templates/gates/shared",
        // 旧版兼容目录
        ".soloforge/knowledge/acceptance_templates",
        ".soloforge/knowledge/review_rules",
        ".soloforge/knowledge/product_profiles",
        ".soloforge/knowledge/templates",
    ];
    // 系统专属目录
    if (includeNew) {
        dirs.push(".soloforge/knowledge/rules/new-system", ".soloforge/knowledge/artifacts/new-system", ".soloforge/templates/artifacts/new-system", ".soloforge/templates/rules/new-system");
    }
    if (includeExisting) {
        dirs.push(".soloforge/knowledge/rules/existing-system", ".soloforge/knowledge/artifacts/existing-system", ".soloforge/templates/artifacts/existing-system", ".soloforge/templates/rules/existing-system", ".soloforge/templates/gates/existing-system");
    }
    for (const dir of dirs) {
        fss.mkdirSync(path.join(projectPath, dir), { recursive: true });
    }
}
export async function cmdInitAuto() {
    debug("CLI", "执行 cmdInitAuto");
    const dryRun = args.includes("--dry-run");
    const projectPathArg = getArgValue("--project-path");
    const projectPath = projectPathArg ? path.resolve(projectPathArg) : process.cwd();
    // 层 1: 确定性指纹探测
    const fp = await detectFingerprint(projectPath);
    // 层 2: 规则推导 → config 草案
    const draft = generateConfigDraft(fp);
    // 层 3: 字段级 evidence
    const evidence = generateConfigEvidence(fp, draft, "auto");
    // 展示探测结果 + evidence
    userInfo("\nSoloForge 自动配置探测结果:");
    userInfo("=".repeat(50));
    for (const [key, field] of Object.entries(evidence.fields)) {
        const icon = field.confidence === "high" ? "✅" : field.confidence === "medium" ? "⚠️" : "❓";
        const valStr = typeof field.value === "object" ? JSON.stringify(field.value) : String(field.value);
        userInfo(`  ${icon} ${key}: ${valStr} (${field.confidence}, ${field.confidence_source})`);
        userInfo(`     证据: ${field.evidence.join(", ")}`);
    }
    userInfo("=".repeat(50));
    userInfo(`综合置信度: ${draft.confidence}`);
    if (draft.advisory_notes.length > 0) {
        userInfo("建议:");
        for (const note of draft.advisory_notes) {
            userInfo(`  - ${note}`);
        }
    }
    // Schema 校验 (advisory)
    const validation = validateConfigDraft(draft);
    if (validation.warnings.length > 0) {
        userInfo("\nschema 建议:");
        for (const w of validation.warnings) {
            userInfo(`  ⚠️ ${w}`);
        }
    }
    if (!validation.valid) {
        userInfo("\nschema 错误:");
        for (const e of validation.errors) {
            userInfo(`  ❌ ${e}`);
        }
        userInfo("\n配置校验失败，请手动运行 `soloforge init --interactive`。");
        return;
    }
    if (dryRun) {
        userInfo("\n[dry-run] 不写入文件。使用不带 --dry-run 的命令执行写入。");
        return;
    }
    // 写入门禁: 所有必要字段必须 high confidence + detected/user_declared/confirmed
    const gate = canAutoWrite(evidence);
    if (!gate.allowed) {
        userInfo(`\n⚠️ 存在低/中置信度配置项，拒绝写入:`);
        for (const f of gate.blockedFields) {
            userInfo(`  - ${f}`);
        }
        userInfo("请使用 `soloforge init --interactive` 或 `soloforge init --blueprint \"...\"` 生成配置。");
        return;
    }
    // 写入配置 + evidence
    await finishInitAutoConfig(projectPath, draft, evidence);
}
export async function finishInitAutoConfig(projectPath, draft, evidence) {
    createProjectDirs(projectPath);
    await writeConfigWithEvidence(projectPath, draft, evidence);
    ensureGitignore(projectPath);
    // 继续执行普通 init 的模板复制和适配器生成
    await copyGlobalPatterns(projectPath);
    await copyKnowledgeTemplates(projectPath);
    await generateAdapterConfigs(projectPath, "claude-code");
}
export async function writeConfigWithEvidence(projectPath, draft, evidence) {
    const configPath = path.join(projectPath, ".soloforge", "config.yaml");
    const evidencePath = path.join(projectPath, ".soloforge", "config.evidence.json");
    // [ENG-1] 写入前校验写入边界
    // CLI init 命令是用户显式触发的，视为已确认
    const { classifyConfigContext, validateWriteBoundary } = await import("../../engine/config/config_write_boundary.js");
    const writeContext = classifyConfigContext(projectPath, { confirmed: true });
    const violations = validateWriteBoundary(writeContext, [configPath, evidencePath]);
    if (violations.length > 0) {
        for (const v of violations)
            userError(`写入边界违规: ${v.reason_zh}`);
        process.exit(1);
    }
    const yamlConfig = {
        schema_version: 1,
        name: draft.name,
        tech_stack: draft.tech_stack,
        product_profile: draft.product_profile,
        repos: [],
        build_commands: draft.build_commands,
        scope: draft.scope,
    };
    atomicWriteFileSync(configPath, YAML.stringify(yamlConfig), "utf-8");
    // 写入旧版 evidence 格式（向后兼容）+ schema v2 条目
    // 一致性保护: evidence 写入失败时回滚 config.yaml
    try {
        atomicWriteFileSync(evidencePath, JSON.stringify(evidence, null, 2), "utf-8");
    }
    catch (evidenceErr) {
        // 回滚: 删除已写入的 config.yaml
        try {
            fss.unlinkSync(configPath);
        }
        catch { }
        throw evidenceErr;
    }
    // 同时写入 schema v2 条目
    // eslint-disable-next-line @typescript-eslint/no-explicit-any -- MCP SDK 桥接/动态 JSON 解析，字段由运行时决定
    const v2Entries = Object.entries(evidence.fields).map(([key, field]) => ({
        field_path: key,
        value_hash: hashConfigValue(JSON.stringify(field.value)),
        source: mapLegacySource(field.confidence_source),
        confidence: field.confidence === "high" ? 1.0 : field.confidence === "medium" ? 0.6 : 0.3,
        evidence_refs: field.evidence ?? [],
        lifetime: "project_persistent",
        collected_at: evidence.generated_at || new Date().toISOString(),
    }));
    // 合并 v2 条目到 evidence 文件
    try {
        const existing = safeJsonParse(fss.readFileSync(evidencePath, "utf-8"));
        if (!existing) {
            internalWarn("CLI", "无法解析已写入的 evidence 文件，跳过 v2 条目合并");
            return;
        }
        existing.entries = v2Entries;
        existing.updated_at = new Date().toISOString();
        atomicWriteFileSync(evidencePath, JSON.stringify(existing, null, 2), "utf-8");
    }
    catch (e) {
        internalWarn("CLI", `更新 evidence 文件失败: ${errorMessage(e)}`);
    }
    userInfo(`\n✅ .soloforge/config.yaml + config.evidence.json created`);
}
export function hashConfigValue(str) {
    return crypto.createHash("sha256").update(str).digest("hex").slice(0, 16);
}
export function mapLegacySource(source) {
    switch (source) {
        case "detected": return "detected";
        case "user_declared": return "user_declared";
        case "confirmed": return "confirmed";
        default: return "knowledge_default";
    }
}
export async function cmdInitBlueprint() {
    debug("CLI", "执行 cmdInitBlueprint");
    const blueprintText = getArgValue("--blueprint");
    if (!blueprintText) {
        userError("❌ --blueprint 需要提供描述文本，例如: soloforge init --blueprint \"Spring Boot + React 的 B2B 内部管理系统\"");
        return;
    }
    const projectPathArg = getArgValue("--project-path");
    const projectPath = projectPathArg ? path.resolve(projectPathArg) : process.cwd();
    const parsed = parseBlueprint(blueprintText);
    if (!parsed.parsed) {
        userInfo("⚠️ 无法从蓝图文本解析技术栈，请使用 --interactive。");
        userInfo("支持的框架关键词: Spring Boot, Go, Rust, Gradle, React, Vue, Angular, Next.js, Nuxt");
        return;
    }
    // 从解析的蓝图构建草稿
    const draft = {
        name: path.basename(projectPath),
        tech_stack: {
            backend: parsed.tech_stack.backend ?? { lang: "", framework: "", version: "" },
            frontend: parsed.tech_stack.frontend ?? { lang: "", framework: "", version: "" },
        },
        product_profile: parsed.product_profile ?? "default",
        build_commands: {
            backend: blueprintBackendCommands(parsed.tech_stack.backend?.framework),
            frontend: blueprintFrontendCommands(parsed.tech_stack.frontend?.framework),
        },
        scope: {
            backend: [],
            frontend: [],
        },
        advisory_notes: [],
        confidence: "high",
    };
    const evidence = generateBlueprintEvidence(blueprintText, draft, projectPath);
    // 创建目录 + 写入配置 + evidence
    createProjectDirs(projectPath);
    await writeConfigWithEvidence(projectPath, draft, evidence);
    ensureGitignore(projectPath);
    await copyGlobalPatterns(projectPath);
    await copyKnowledgeTemplates(projectPath);
    await generateAdapterConfigs(projectPath, "claude-code");
}
export function blueprintBackendCommands(framework) {
    switch (framework) {
        case "spring-boot": return { build: "./mvnw compile -q", test: "./mvnw test -q", full: "./mvnw verify -q" };
        case "gradle": return { build: "./gradlew compileJava", test: "./gradlew test", full: "./gradlew check" };
        case "stdlib": return { build: "go build ./...", test: "go test ./...", full: "go test -race ./..." };
        case "cargo": return { build: "cargo build", test: "cargo test", full: "cargo test --all" };
        default: return { build: "echo 'no backend build'", test: "echo 'no backend tests'", full: "echo 'no backend'" };
    }
}
export function blueprintFrontendCommands(framework) {
    switch (framework) {
        case "react":
        case "vue":
            return { build: "npm run build", test: "npm test", full: "npm run build && npm test" };
        case "angular":
            return { build: "npx ng build", test: "npx ng test", full: "npx ng build && npx ng test" };
        default: return { build: "echo 'no frontend build'", test: "echo 'no frontend tests'", full: "echo 'no frontend'" };
    }
}
export async function cmdInit() {
    debug("CLI", "执行 cmdInit");
    const interactive = args.includes("--interactive");
    const adapter = getArgValue("--adapter") || "claude-code";
    const projectPathArg = getArgValue("--project-path");
    const projectPath = projectPathArg ? path.resolve(projectPathArg) : process.cwd();
    const systemType = getArgValue("--system-type");
    // 校验 --system-type
    if (systemType && systemType !== "新系统" && systemType !== "老系统") {
        userInfo("⚠️ --system-type 仅支持 '新系统' 或 '老系统'");
        process.exit(1);
    }
    // 创建目录（包含全部系统类型目录，由 cmdInit 通用入口使用）
    createProjectDirs(projectPath, { includeNewSystem: true, includeExistingSystem: true });
    // 仅 --interactive 模式生成 config.yaml + evidence；普通 init 不再生成
    if (interactive) {
        const config = await interactiveConfig(projectPath);
        if (config) {
            // config 结构为 { draft, evidence }
            await writeConfigWithEvidence(projectPath, config.draft, config.evidence);
        }
        else if (!process.stdin.isTTY) {
            userInfo("⚠️ interactive requires TTY. 请使用 --auto 或 --blueprint。");
        }
    }
    // 生成 .mcp.json（SoloForge + Playwright）
    if (adapter === "claude-code" || adapter === "all") {
        const mcpPath = path.join(projectPath, ".mcp.json");
        if (!fss.existsSync(mcpPath)) {
            const mcpConfig = {
                mcpServers: {
                    soloforge: {
                        command: "soloforge",
                        args: ["mcp"],
                        env: { SOLOFORGE_PROJECT: projectPath },
                    },
                    playwright: {
                        command: "npx",
                        args: ["@playwright/mcp@latest", "--headless"],
                    },
                },
            };
            atomicWriteFileSync(mcpPath, JSON.stringify(mcpConfig, null, 2), "utf-8");
            userInfo("✅ .mcp.json 已创建（soloforge + playwright）");
        }
        // 生成 hooks
        await cmdGenerateHooks(projectPath);
        // 生成 CLAUDE.md
        await cmdGenerateClaudeMdInner(projectPath);
    }
    // 生成 Trae IDE 配置
    if (adapter === "trae" || adapter === "all") {
        await cmdGenerateTraeInner(projectPath);
        userInfo("💡 提示: 使用项目级 .trae/ 配置需在 Trae 中开启 beta flag");
    }
    // 生成 Codex App 配置
    if (adapter === "codex" || adapter === "all") {
        await cmdGenerateCodexInner(projectPath);
    }
    // 复制模板 + 适配器配置（共享逻辑）
    await copyGlobalPatterns(projectPath);
    await copyKnowledgeTemplates(projectPath);
    // 复制管线模板（shared + 系统专属）
    await copyPipelineTemplates(projectPath, systemType);
    // 确保 .gitignore 包含必要条目
    ensureGitignore(projectPath);
    userInfo(`\n✅ SoloForge 初始化完成 (适配器: ${adapter})。${adapter === "trae" ? "请打开 Trae IDE 开始使用。" :
        adapter === "codex" ? "请打开 Codex App 开始使用。" :
            adapter === "all" ? "可在 Claude Code、Trae IDE 或 Codex App 中使用。" :
                "请打开 Claude Code 开始使用。"}`);
}
export async function copyGlobalPatterns(_projectPath) {
    const { copyPatternsToGlobal } = await import("../../engine/templates/template_init_sync.js");
    const globalDir = getGlobalPatternsDir();
    const templatesRoot = path.resolve(import.meta.dirname, "..", "..", "..");
    const result = await copyPatternsToGlobal(templatesRoot, globalDir);
    const parts = [];
    if (result.copied > 0)
        parts.push(`新增 ${result.copied} 个`);
    if (result.skipped > 0)
        parts.push(`跳过 ${result.skipped} 个（已存在）`);
    if (parts.length > 0) {
        userInfo(`✅ 全局模板 ~/.soloforge/patterns/: ${parts.join("，")}`);
    }
}
export async function copyKnowledgeTemplates(projectPath) {
    const { copyKnowledgeToProject } = await import("../../engine/templates/template_init_sync.js");
    const templatesRoot = path.resolve(import.meta.dirname, "..", "..", "..");
    const result = await copyKnowledgeToProject(templatesRoot, projectPath);
    const parts = [];
    if (result.copied > 0)
        parts.push(`${result.copied} 个新增`);
    if (result.updated > 0)
        parts.push(`${result.updated} 个已更新`);
    if (result.skipped_up_to_date > 0)
        parts.push(`${result.skipped_up_to_date} 个已是最新`);
    if (result.skipped_user_modified > 0)
        parts.push(`${result.skipped_user_modified} 个用户修改跳过`);
    if (result.skipped_internal > 0)
        parts.push(`${result.skipped_internal} 个内部资产已跳过`);
    if (result.skipped_no_contract > 0)
        parts.push(`${result.skipped_no_contract} 个无合同已跳过`);
    if (parts.length > 0) {
        userInfo(`✅ 知识模板: ${parts.join("，")}`);
    }
}
export async function copyPipelineTemplates(projectPath, systemType) {
    const { copyPipelineTemplatesToProject } = await import("../../engine/templates/template_init_sync.js");
    const templatesRoot = path.resolve(import.meta.dirname, "..", "..", "..");
    const result = await copyPipelineTemplatesToProject(templatesRoot, projectPath, systemType);
    const parts = [];
    if (result.copied > 0)
        parts.push(`${result.copied} 个新增`);
    if (result.updated > 0)
        parts.push(`${result.updated} 个已更新`);
    if (result.skipped_modified > 0)
        parts.push(`${result.skipped_modified} 个已修改跳过`);
    if (result.skipped_exists > 0)
        parts.push(`${result.skipped_exists} 个已存在`);
    const typeLabel = systemType ?? "全部";
    if (parts.length > 0) {
        userInfo(`✅ 管线模板 (${typeLabel}): ${parts.join("，")}`);
    }
}
export async function generateAdapterConfigs(projectPath, adapter) {
    if (adapter === "claude-code" || adapter === "all") {
        const mcpPath = path.join(projectPath, ".mcp.json");
        if (!fss.existsSync(mcpPath)) {
            const mcpConfig = {
                mcpServers: {
                    soloforge: { command: "soloforge", args: ["mcp"], env: { SOLOFORGE_PROJECT: projectPath } },
                    playwright: { command: "npx", args: ["@playwright/mcp@latest", "--headless"] },
                },
            };
            atomicWriteFileSync(mcpPath, JSON.stringify(mcpConfig, null, 2), "utf-8");
            userInfo("✅ .mcp.json 已创建（soloforge + playwright）");
        }
        await cmdGenerateHooks(projectPath);
        await cmdGenerateClaudeMdInner(projectPath);
    }
}
export function ensureGitignore(projectPath) {
    const gitignorePath = path.join(projectPath, ".gitignore");
    const requiredEntries = [".mcp.json", ".soloforge/"];
    let content = "";
    if (fss.existsSync(gitignorePath)) {
        content = fss.readFileSync(gitignorePath, "utf-8");
    }
    const lines = content.split("\n");
    const missing = requiredEntries.filter((entry) => !lines.some((l) => l.trim() === entry));
    if (missing.length > 0) {
        const addition = (content.endsWith("\n") ? "" : "\n") + missing.join("\n") + "\n";
        fss.appendFileSync(gitignorePath, addition, "utf-8");
        userInfo(`✅ .gitignore 已更新: ${missing.join(", ")}`);
    }
}
//# sourceMappingURL=init.js.map