import { knowledgeStore } from '../../storage/index.js';
import { scaffoldLintConfig } from './lint-scaffolder.js';
import { buildProjectSections } from './claude-md-generator.js';
import { injectSddIntoClaude } from './helpers.js';
import { handleInitConstitution } from '../init-constitution/handler.js';
import { runRulesWriter } from './rules-writer.js';
import { runGitSetup } from './git-setup.js';
import { generateAndWriteRules } from './lifecycle-helpers.js';
import { generatePlanuSection, injectPlanuSection } from './planu-workflow-generator.js';
import { configurePlanuHooks } from './hooks-configurator.js';
import { generateWorkflowRulesIfMissing, generateAgentTeamsRulesIfMissing, generateModeRulesIfMissing, generateResponseStyleRulesIfMissing, } from './rules-generator.js';
import { generateCompactSkillIfMissing } from './skills-writer.js';
import { generateFindSkillsIfMissing } from './find-skills-writer.js';
import { injectPlanuAutoStage } from '../../engine/git-hook-injector.js';
import { generateAgentFilesIfMissing } from './agents-md-writer.js';
import { detectHost } from '../../engine/host-detection/detect-host.js';
import { generateConventionsMdIfMissing } from './conventions-writer.js';
import { generateMultiTeammateReviewSkillIfMissing } from './skills-multi-teammate-review-writer.js';
import { writeSkillRegistry, ALL_SKILL_SOURCES, } from '../../storage/skill-registry-storage.js';
import { generateWorkflowSkills } from '../../engine/skill-generator/workflow-skill-generator.js';
/**
 * Write all scaffold files to disk:
 * - AI rules files (platform-specific)
 * - Git hooks + .gitignore
 * - Constitution (if missing)
 * - CLAUDE.md SDD injection
 * - ESLint/Prettier config
 * - Architecture rules
 */
// eslint-disable-next-line complexity
export async function runScaffoldWriter(projectPath, projectId, knowledge, recommendedSkills, permissionsMode, pluginsMode) {
    // Generate and write AI rules files
    const rulesResult = await runRulesWriter(projectPath, projectId, knowledge, recommendedSkills);
    // Git setup: hooks, flow detection, .gitignore (SPEC-001)
    const gitResult = await runGitSetup(projectPath, projectId);
    // Auto-initialize constitution (best-effort, only if missing)
    let constitutionInitialized = false;
    const existingConstitution = await knowledgeStore.getConstitution(projectId);
    if (!existingConstitution) {
        try {
            const constResult = await handleInitConstitution({ projectId, autoDetect: true });
            constitutionInitialized = !constResult.isError;
        }
        catch {
            /* best-effort */
        }
    }
    let detectedAssetHosts = [];
    let hostRulesWritten = 0;
    let hostSkillsWritten = 0;
    let opencodeConfigScaffolded = false;
    try {
        const { installInitHostAssets } = await import('./host-assets-writer.js');
        const hostAssets = await installInitHostAssets(projectPath, knowledge);
        detectedAssetHosts = hostAssets.detectedHosts;
        hostRulesWritten = hostAssets.rulesInstalled.length;
        hostSkillsWritten = hostAssets.skillsInstalled.length;
        opencodeConfigScaffolded = hostAssets.opencodeConfigured;
    }
    catch {
        /* best-effort */
    }
    const shouldWriteClaudeAssets = detectedAssetHosts.includes('claude-code');
    // Auto-inject SDD workflow into CLAUDE.md (best-effort, idempotent)
    let claudeMdUpdated = false;
    if (shouldWriteClaudeAssets) {
        try {
            const projectSections = buildProjectSections(knowledge);
            claudeMdUpdated = await injectSddIntoClaude(projectPath, projectSections);
        }
        catch {
            /* best-effort */
        }
    }
    // SPEC-178: Scaffold ESLint and Prettier config if missing (best-effort)
    let eslintCreated = false;
    let prettierCreated = false;
    let lintSuggestions = [];
    try {
        const lintResult = await scaffoldLintConfig(projectPath, knowledge);
        eslintCreated = lintResult.eslintCreated;
        prettierCreated = lintResult.prettierCreated;
        lintSuggestions = lintResult.suggestions;
    }
    catch {
        /* best-effort — don't fail init_project */
    }
    // SPEC-187: Generate AI-tool-specific architecture rules (best-effort)
    const { written: architectureRulesWritten, skipped: architectureRulesSkipped } = generateAndWriteRules(projectPath);
    // SPEC-263: Inject Planu SDD Workflow section into CLAUDE.md (idempotent, best-effort)
    let planuWorkflowInjected = false;
    if (shouldWriteClaudeAssets) {
        try {
            const claudeMdPath = `${projectPath}/CLAUDE.md`;
            const section = generatePlanuSection(projectPath, projectId);
            await injectPlanuSection(claudeMdPath, section);
            planuWorkflowInjected = true;
        }
        catch {
            /* best-effort */
        }
    }
    // SPEC-263: Configure Planu hooks in .claude.json (idempotent, best-effort)
    let planuHooksConfigured = false;
    if (shouldWriteClaudeAssets) {
        try {
            planuHooksConfigured = await configurePlanuHooks(projectPath);
        }
        catch {
            /* best-effort */
        }
    }
    // SPEC-263: Write .claude/rules/planu-workflow.md if missing (best-effort)
    let planuRulesWritten = false;
    if (shouldWriteClaudeAssets) {
        try {
            planuRulesWritten = await generateWorkflowRulesIfMissing(projectPath);
        }
        catch {
            /* best-effort */
        }
    }
    // SPEC-291: Write .claude/rules/agent-teams.md if missing (best-effort)
    let agentTeamsRulesWritten = false;
    if (shouldWriteClaudeAssets) {
        try {
            agentTeamsRulesWritten = await generateAgentTeamsRulesIfMissing(projectPath);
        }
        catch {
            /* best-effort */
        }
    }
    // SPEC-494: Write .claude/rules/planu-modes.md if missing (best-effort)
    let modeRulesWritten = false;
    if (shouldWriteClaudeAssets) {
        try {
            modeRulesWritten = await generateModeRulesIfMissing(projectPath);
        }
        catch {
            /* best-effort */
        }
    }
    // SPEC-517: Write .claude/rules/planu-response-style.md if missing (best-effort)
    let responseStyleRulesWritten = false;
    if (shouldWriteClaudeAssets) {
        try {
            responseStyleRulesWritten = await generateResponseStyleRulesIfMissing(projectPath);
        }
        catch {
            /* best-effort */
        }
    }
    // SPEC-519: Write .claude/skills/compact.md if missing (best-effort)
    let compactSkillWritten = false;
    if (shouldWriteClaudeAssets) {
        try {
            compactSkillWritten = await generateCompactSkillIfMissing(projectPath);
        }
        catch {
            /* best-effort */
        }
    }
    // SPEC-655: Write .claude/skills/find-skills.md if missing (best-effort, idempotent)
    if (shouldWriteClaudeAssets) {
        try {
            await generateFindSkillsIfMissing(projectPath);
        }
        catch {
            /* best-effort */
        }
    }
    // SPEC-347: Inject git auto-stage snippet for planu HTML files (best-effort)
    let gitAutoStageInjected = false;
    try {
        const autoStageResult = await injectPlanuAutoStage(projectPath);
        gitAutoStageInjected = autoStageResult.injected;
    }
    catch {
        /* best-effort */
    }
    // SPEC-518: Generate AGENTS.md + .cursorrules + .windsurfrules (best-effort, idempotent)
    // SPEC-972: Pass detected host so AGENTS.md tool list is filtered by capability.
    let agentsMdWritten = false;
    let cursorRulesWritten = false;
    try {
        const detectedHost = detectHost();
        const hostForFilter = detectedHost === 'codex' ? 'codex' : undefined;
        const agentResult = await generateAgentFilesIfMissing(projectPath, hostForFilter);
        agentsMdWritten = agentResult.agentsMdWritten;
        cursorRulesWritten = agentResult.cursorRulesWritten;
    }
    catch {
        /* best-effort */
    }
    // SPEC-648: Generate per-client files (Cursor MDC, Codex skill) based on detected client
    try {
        const { generatePerClientFiles } = await import('./per-client-files-writer.js');
        await generatePerClientFiles(projectPath);
    }
    catch {
        /* best-effort */
    }
    // SPEC-530: Generate .claude/rules/conventions.md (best-effort, idempotent)
    let conventionsMdWritten = false;
    if (shouldWriteClaudeAssets) {
        try {
            conventionsMdWritten = await generateConventionsMdIfMissing(projectPath, knowledge);
        }
        catch {
            /* best-effort */
        }
    }
    // SPEC-591: Scaffold .gemini/ if a Gemini workspace marker is present (best-effort, idempotent)
    let geminiConfigScaffolded = false;
    try {
        const { detectGeminiWorkspace, scaffoldGeminiConfig } = await import('../../hosts/gemini/index.js');
        const geminiMarker = await detectGeminiWorkspace(projectPath);
        if (geminiMarker.detected) {
            const geminiResult = await scaffoldGeminiConfig(projectPath);
            geminiConfigScaffolded = geminiResult.modified;
        }
    }
    catch {
        /* best-effort */
    }
    // SPEC-593: Write .claude/skills/planu-multi-teammate-review.md if missing (best-effort, idempotent)
    let multiTeammateReviewSkillWritten = false;
    if (shouldWriteClaudeAssets) {
        try {
            multiTeammateReviewSkillWritten =
                await generateMultiTeammateReviewSkillIfMissing(projectPath);
        }
        catch {
            /* best-effort */
        }
    }
    // SPEC-592: Scaffold Codex workspace config if Codex env is detected (best-effort, no-op outside Codex)
    let codexConfigScaffolded = false;
    try {
        const { detectCodexWorkspace } = await import('../../hosts/codex/workspace-scope.js');
        const { scaffoldCodexConfig } = await import('../../hosts/codex/config-scaffold.js');
        const markers = detectCodexWorkspace(projectPath);
        const isCodexEnv = markers.hasWorkspaceEnv || markers.hasCodexEnv || markers.isEnterprise;
        if (isCodexEnv || markers.configDir !== undefined) {
            await scaffoldCodexConfig(projectPath);
            codexConfigScaffolded = true;
        }
    }
    catch {
        /* best-effort */
    }
    // SPEC-588: Scaffold .claude/agents/ and .claude/skills/planu-* when Claude Code detected
    // (idempotent — skips files already up-to-date; best-effort, no-op elsewhere)
    let planuSubagentsScaffolded = false;
    let planuUxSkillsScaffolded = 0;
    if (shouldWriteClaudeAssets) {
        try {
            const { scaffoldPlanuSubagents, scaffoldPlanuSkills } = await import('../../hosts/claude-code/ux/index.js');
            const [subagentResult, skillResult] = await Promise.all([
                scaffoldPlanuSubagents(projectPath),
                scaffoldPlanuSkills(projectPath),
            ]);
            planuSubagentsScaffolded = subagentResult.created.length > 0;
            planuUxSkillsScaffolded = skillResult.created.length;
        }
        catch {
            /* best-effort */
        }
    }
    // SPEC-594: Configure .claude/settings.json permissions (opt-in; idempotent; best-effort)
    let permissionsConfigured = null;
    if (permissionsMode !== undefined) {
        try {
            const { handleConfigurePermissions } = await import('../configure-permissions.js');
            await handleConfigurePermissions({ projectPath, mode: permissionsMode });
            permissionsConfigured = true;
        }
        catch {
            permissionsConfigured = false;
        }
    }
    // SPEC-596: Register Anthropic marketplace + install stack-aware plugins (opt-in; idempotent; best-effort)
    // Skips silently when `claude` CLI is absent — no crash, no blocking.
    let pluginsInstalled = null;
    if (pluginsMode !== undefined) {
        try {
            const { ensureAnthropicMarketplaceRegistered, getRecommendedForStack, matchStackSignals, installPlugins: installFn, } = await import('../../engine/plugin-installer/index.js');
            const signals = matchStackSignals(knowledge.stack);
            const recommended = await getRecommendedForStack(signals, pluginsMode);
            const [mktStatus, outcome] = await Promise.all([
                ensureAnthropicMarketplaceRegistered(false),
                installFn(recommended, false),
            ]);
            pluginsInstalled = {
                marketplaceAdded: mktStatus.registered,
                installed: outcome.installed,
                skipped: outcome.skipped,
                failed: outcome.failed,
            };
        } /* v8 ignore next */
        catch {
            /* best-effort — never fail init_project due to missing claude CLI */
        }
    }
    // SPEC-680: Create .planu/skill-registry.json if it does not exist (idempotent, best-effort)
    try {
        const { readFile: readFileFn } = await import('node:fs/promises');
        const { join: joinFn } = await import('node:path');
        const registryFilePath = joinFn(projectPath, '.planu', 'skill-registry.json');
        const existing = await readFileFn(registryFilePath, 'utf-8').catch(() => null);
        if (existing === null) {
            const now = new Date().toISOString();
            const initialRegistry = {
                createdAt: now,
                updatedAt: now,
                sources: [...ALL_SKILL_SOURCES],
                installed: {},
            };
            await writeSkillRegistry(projectPath, initialRegistry);
        }
    }
    catch {
        /* best-effort — never fail init_project */
    }
    // SPEC-685: Generate all 22 workflow skill files (idempotent, best-effort)
    let workflowSkillsWritten = 0;
    if (shouldWriteClaudeAssets) {
        try {
            const skillResult = await generateWorkflowSkills(projectPath, knowledge);
            workflowSkillsWritten = skillResult.written.length;
        }
        catch {
            /* best-effort — never fail init_project */
        }
    }
    // SPEC-587: Install spec-sanctity PostToolUse hook when Claude Code is detected
    // (idempotent — overwrites only when content differs; best-effort, no-op elsewhere)
    let specSanctityHookInstalled = false;
    try {
        const { writeFile: writeFileFn, mkdir: mkdirFn, access: accessFn, readFile: readFileFn, } = await import('node:fs/promises');
        const { join: joinFn } = await import('node:path');
        const { detectAgentTeamsSupport } = await import('../../hosts/claude-code/runtime/agent-teams-adapter.js');
        const { homedir } = await import('node:os');
        // Detect Claude Code: .claude/ dir at project root OR ~/.claude/teams/ exists
        const hasLocalClaudeDir = await accessFn(joinFn(projectPath, '.claude'))
            .then(() => true)
            .catch(() => false);
        const hasTeamsDir = await detectAgentTeamsSupport();
        if (hasLocalClaudeDir || hasTeamsDir) {
            const hooksDir = joinFn(projectPath, '.claude', 'hooks');
            await mkdirFn(hooksDir, { recursive: true });
            const dest = joinFn(hooksDir, 'planu-spec-sanctity.sh');
            // Read the canonical template from src/config/hook-templates/
            const templatePath = joinFn(
            // Resolve relative to this file's compiled location in dist/ or src/
            homedir(), '.claude', 'projects', '-Users-kevin-Documents-desarrollo-sdd-mcp-server');
            void templatePath; // unused — we read from a fixed relative location
            // Read template from its canonical src/ location
            const { fileURLToPath } = await import('node:url');
            const currentDir = joinFn(fileURLToPath(new URL('.', import.meta.url)), '../../config/hook-templates');
            const templateContent = await readFileFn(joinFn(currentDir, 'planu-spec-sanctity.sh'), 'utf-8').catch(() => null);
            if (templateContent !== null) {
                // Idempotent: only write if content differs
                const existing = await readFileFn(dest, 'utf-8').catch(() => null);
                if (existing !== templateContent) {
                    await writeFileFn(dest, templateContent, { mode: 0o755 });
                }
                specSanctityHookInstalled = true;
            }
        }
    }
    catch {
        /* best-effort */
    }
    return {
        platform: rulesResult.platform,
        generatedRules: rulesResult.generatedRules,
        rulesWritten: rulesResult.rulesWritten,
        additionalFilesWritten: rulesResult.additionalFilesWritten,
        hooksInstalled: gitResult.hooksInstalled,
        gitFlowType: gitResult.gitFlowType,
        gitignoreUpdated: gitResult.gitignoreUpdated,
        gitRepoDetected: gitResult.gitRepoDetected,
        constitutionInitialized,
        claudeMdUpdated,
        eslintCreated,
        prettierCreated,
        lintSuggestions,
        architectureRulesWritten,
        architectureRulesSkipped,
        planuWorkflowInjected,
        planuHooksConfigured,
        planuRulesWritten,
        agentTeamsRulesWritten,
        modeRulesWritten,
        responseStyleRulesWritten,
        compactSkillWritten,
        gitAutoStageInjected,
        agentsMdWritten,
        cursorRulesWritten,
        conventionsMdWritten,
        geminiConfigScaffolded,
        codexConfigScaffolded,
        multiTeammateReviewSkillWritten,
        specSanctityHookInstalled,
        planuSubagentsScaffolded,
        planuUxSkillsScaffolded,
        permissionsConfigured,
        pluginsInstalled,
        workflowSkillsWritten,
        detectedAssetHosts,
        hostRulesWritten,
        hostSkillsWritten,
        opencodeConfigScaffolded,
    };
}
//# sourceMappingURL=scaffold-writer.js.map