/*
 * Copyright 2026, Jaime Terrats.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import { existsSync, readdirSync, readFileSync, rmSync } from 'node:fs';
import { join } from 'node:path';
import { checkbox, select } from '@inquirer/prompts';
import { hasManagedBlocks } from '../services/managed-blocks.js';
import { ALL_PROFILES, CLOUD_PROFILE_IDS, FUNCTIONAL_ROLE_IDS, PROFILE_ID_ALIASES, ROLE_PROFILE_IDS, TECHNICAL_ROLE_IDS, developerProfile } from '../profiles/index.js';
import { SUPPORTED_TOOLS } from '../types/index.js';
import { PLUGIN_VERSION } from '../version.js';
const VALID_PROFILE_IDS = ALL_PROFILES.map((p) => p.id);
export const STALE_VERSION_MDC = /^pluginVersion: "([^"]+)"/m;
export const STALE_VERSION_FLAT = /<!-- setup-agents: ([^\s]+) -->/;
// Derived from ALL_PROFILES so it never drifts when new profiles are added.
const PROFILE_FILE_MAP = Object.fromEntries(ALL_PROFILES.map((p) => [p.ruleFile, p.id]));
// Known per-profile filenames for claude (.claude/rules/) and codex (.codex/).
// Pattern: <profile.id>.md
const KNOWN_PROFILE_MD = new Set(ALL_PROFILES.map((p) => `${p.id}.md`));
export function detectTools(cwd) {
    const detected = [];
    if (existsSync(join(cwd, '.cursor')))
        detected.push('cursor');
    if (existsSync(join(cwd, '.vscode')))
        detected.push('vscode');
    if (existsSync(join(cwd, 'AGENTS.md')) || existsSync(join(cwd, '.codex')))
        detected.push('codex');
    if (existsSync(join(cwd, 'CLAUDE.md')) || existsSync(join(cwd, '.claude', 'rules')))
        detected.push('claude');
    if (existsSync(join(cwd, '.a4drules')))
        detected.push('agentforce');
    if (existsSync(join(cwd, '.windsurfrules')) || existsSync(join(cwd, '.windsurf')))
        detected.push('windsurf');
    if (existsSync(join(cwd, '.idea', 'ai-prompts')))
        detected.push('jetbrains');
    return detected;
}
export async function resolveTools(cwd, flagValue, workspaceTools, msgs) {
    if (flagValue)
        return [flagValue];
    const detected = detectTools(cwd);
    if (workspaceTools?.length) {
        const merged = new Set(workspaceTools);
        for (const tool of detected)
            merged.add(tool);
        return [...merged];
    }
    if (detected.length > 0)
        return detected;
    if (!process.stdin.isTTY)
        return [...SUPPORTED_TOOLS];
    const selected = await checkbox({
        message: msgs.getMessage('prompt.selectTools'),
        choices: SUPPORTED_TOOLS.map((tool) => ({ value: tool, name: tool })),
    });
    return selected.length > 0 ? selected : [...SUPPORTED_TOOLS];
}
async function runGuidedOnboarding(cwd, msgs) {
    const roleProfiles = ALL_PROFILES.filter((p) => ROLE_PROFILE_IDS.includes(p.id));
    const cloudProfiles = ALL_PROFILES.filter((p) => CLOUD_PROFILE_IDS.includes(p.id));
    const autoDetectedRoles = new Set(roleProfiles.filter((p) => p.detect?.(cwd)).map((p) => p.id));
    const autoDetectedClouds = new Set(cloudProfiles.filter((p) => p.detect?.(cwd)).map((p) => p.id));
    const technicalRoles = roleProfiles.filter((p) => TECHNICAL_ROLE_IDS.includes(p.id));
    const functionalRoles = roleProfiles.filter((p) => FUNCTIONAL_ROLE_IDS.includes(p.id));
    const otherRoles = roleProfiles.filter((p) => !TECHNICAL_ROLE_IDS.includes(p.id) && !FUNCTIONAL_ROLE_IDS.includes(p.id));
    const roleChoices = [
        { value: '', name: '── Technical ──', disabled: '' },
        ...technicalRoles.map((p) => ({ value: p.id, name: `  ${p.label}`, checked: autoDetectedRoles.has(p.id) })),
        { value: '', name: '── Functional ──', disabled: '' },
        ...functionalRoles.map((p) => ({ value: p.id, name: `  ${p.label}`, checked: autoDetectedRoles.has(p.id) })),
        ...(otherRoles.length > 0
            ? [
                { value: '', name: '── Platform ──', disabled: '' },
                ...otherRoles.map((p) => ({ value: p.id, name: `  ${p.label}`, checked: autoDetectedRoles.has(p.id) })),
            ]
            : []),
    ];
    const selectedRoles = (await checkbox({
        message: msgs.getMessage('prompt.onboarding.roles'),
        choices: roleChoices,
    })).filter((id) => id.length > 0);
    const selectedClouds = await checkbox({
        message: msgs.getMessage('prompt.onboarding.clouds'),
        choices: cloudProfiles.map((p) => ({ value: p.id, name: p.label, checked: autoDetectedClouds.has(p.id) })),
    });
    const useAdvanced = await select({
        message: msgs.getMessage('prompt.onboarding.advanced'),
        choices: [
            { value: false, name: msgs.getMessage('prompt.onboarding.advanced.no') },
            { value: true, name: msgs.getMessage('prompt.onboarding.advanced.yes') },
        ],
    });
    if (useAdvanced) {
        const allSelected = new Set([...selectedRoles, ...selectedClouds]);
        const selected = await checkbox({
            message: msgs.getMessage('prompt.selectProfiles'),
            choices: ALL_PROFILES.map((p) => ({ value: p.id, name: p.label, checked: allSelected.has(p.id) })),
        });
        return selected;
    }
    return [...selectedRoles, ...selectedClouds];
}
export async function resolveProfiles(cwd, flagValue, msgs, warnFn) {
    if (flagValue) {
        const rawIds = flagValue.split(',').map((s) => s.trim());
        const ids = rawIds.map((id) => (PROFILE_ID_ALIASES[id] ?? id));
        const invalid = ids.filter((id) => !VALID_PROFILE_IDS.includes(id));
        if (invalid.length > 0) {
            warnFn?.(msgs.getMessage('warn.unknownProfiles', [invalid.join(', '), VALID_PROFILE_IDS.join(', ')]));
        }
        const profiles = ALL_PROFILES.filter((p) => ids.includes(p.id));
        return { profiles, usedDefault: false };
    }
    if (!process.stdin.isTTY) {
        return { profiles: [developerProfile], usedDefault: true };
    }
    const selected = await runGuidedOnboarding(cwd, msgs);
    if (selected.length === 0)
        return { profiles: [developerProfile], usedDefault: true };
    return { profiles: ALL_PROFILES.filter((p) => selected.includes(p.id)), usedDefault: false };
}
export function findStaleFiles(cwd) {
    const stale = [];
    const checkFile = (filePath, tool, pattern) => {
        if (!existsSync(filePath))
            return;
        const content = readFileSync(filePath, 'utf8');
        const match = pattern.exec(content);
        // For flat-marker files: skip entirely if the marker is absent — not our file.
        if (pattern === STALE_VERSION_FLAT && !match)
            return;
        if (!match || match[1] !== PLUGIN_VERSION) {
            const managedBlocks = hasManagedBlocks(content);
            stale.push({
                file: filePath,
                tool,
                version: match?.[1] ?? null,
                managedBlocks,
                updateMode: managedBlocks ? 'managed-blocks' : 'full-file',
                availableActions: ['check', 'dry-run', 'update'],
            });
        }
    };
    const rulesDir = join(cwd, '.cursor', 'rules');
    if (existsSync(rulesDir)) {
        for (const file of readdirSync(rulesDir).filter((f) => f.endsWith('.mdc') && PROFILE_FILE_MAP[f])) {
            checkFile(join(rulesDir, file), 'cursor', STALE_VERSION_MDC);
        }
    }
    checkFile(join(cwd, '.github', 'copilot-instructions.md'), 'vscode', STALE_VERSION_FLAT);
    checkFile(join(cwd, 'AGENTS.md'), 'codex', STALE_VERSION_FLAT);
    const codexDir = join(cwd, '.codex');
    if (existsSync(codexDir)) {
        for (const file of readdirSync(codexDir).filter((f) => f.endsWith('.md') && KNOWN_PROFILE_MD.has(f))) {
            checkFile(join(codexDir, file), 'codex', STALE_VERSION_FLAT);
        }
    }
    checkFile(join(cwd, 'CLAUDE.md'), 'claude', STALE_VERSION_FLAT);
    const claudeRulesDir = join(cwd, '.claude', 'rules');
    if (existsSync(claudeRulesDir)) {
        for (const file of readdirSync(claudeRulesDir).filter((f) => f.endsWith('.md') && KNOWN_PROFILE_MD.has(f))) {
            checkFile(join(claudeRulesDir, file), 'claude', STALE_VERSION_FLAT);
        }
    }
    checkFile(join(cwd, '.windsurfrules'), 'windsurf', STALE_VERSION_FLAT);
    const jetbrainsPromptsDir = join(cwd, '.idea', 'ai-prompts');
    if (existsSync(jetbrainsPromptsDir)) {
        for (const file of readdirSync(jetbrainsPromptsDir).filter((f) => f.endsWith('.md'))) {
            checkFile(join(jetbrainsPromptsDir, file), 'jetbrains', STALE_VERSION_FLAT);
        }
    }
    const a4dDir = join(cwd, '.a4drules');
    if (existsSync(a4dDir)) {
        for (const file of readdirSync(a4dDir).filter((f) => f.endsWith('.md'))) {
            checkFile(join(a4dDir, file), 'agentforce', STALE_VERSION_FLAT);
        }
        const workflowsDir = join(a4dDir, 'workflows');
        if (existsSync(workflowsDir)) {
            for (const file of readdirSync(workflowsDir).filter((f) => f.endsWith('.md'))) {
                checkFile(join(workflowsDir, file), 'agentforce', STALE_VERSION_FLAT);
            }
        }
    }
    // Prompt registry — .generated-prompts/*.md use flat version marker
    const generatedPromptsDir = join(cwd, '.generated-prompts');
    if (existsSync(generatedPromptsDir)) {
        for (const file of readdirSync(generatedPromptsDir).filter((f) => f.endsWith('.md'))) {
            checkFile(join(generatedPromptsDir, file), 'cursor', STALE_VERSION_FLAT);
        }
    }
    // Playbooks — .setup-agents/playbooks/*.md
    const playbooksDir = join(cwd, '.setup-agents', 'playbooks');
    if (existsSync(playbooksDir)) {
        for (const file of readdirSync(playbooksDir).filter((f) => f.endsWith('.md'))) {
            checkFile(join(playbooksDir, file), 'cursor', STALE_VERSION_FLAT);
        }
    }
    // Skills — .setup-agents/skills/**/*.md
    const skillsDir = join(cwd, '.setup-agents', 'skills');
    if (existsSync(skillsDir)) {
        for (const dir of readdirSync(skillsDir, { withFileTypes: true }).filter((d) => d.isDirectory())) {
            const skillPath = join(skillsDir, dir.name);
            for (const file of readdirSync(skillPath).filter((f) => f.endsWith('.md'))) {
                checkFile(join(skillPath, file), 'cursor', STALE_VERSION_FLAT);
            }
        }
    }
    return stale;
}
export function findContentDrift(cwd) {
    const drift = [];
    const rulesDir = join(cwd, '.cursor', 'rules');
    if (!existsSync(rulesDir))
        return drift;
    for (const profile of ALL_PROFILES) {
        const filePath = join(rulesDir, profile.ruleFile);
        if (!existsSync(filePath))
            continue;
        const diskContent = readFileSync(filePath, 'utf8');
        const expectedBody = profile.ruleContent();
        const expectedContent = injectCursorVersion(expectedBody, PLUGIN_VERSION);
        const versionMatch = STALE_VERSION_MDC.exec(diskContent);
        if (!versionMatch || versionMatch[1] !== PLUGIN_VERSION) {
            drift.push({ file: filePath, tool: 'cursor', reason: 'version' });
        }
        else if (normalizeForCompare(diskContent) !== normalizeForCompare(expectedContent)) {
            drift.push({ file: filePath, tool: 'cursor', reason: 'content' });
        }
    }
    return drift;
}
function injectCursorVersion(content, version) {
    if (content.startsWith('---')) {
        return content.replace(/^(---)/, `---\npluginVersion: "${version}"`);
    }
    return `<!-- setup-agents: ${version} -->\n${content}`;
}
function normalizeForCompare(content) {
    return content
        .replace(/pluginVersion: "[^"]*"/g, '')
        .replace(/<!-- setup-agents: [^\s]+ -->/g, '')
        .replace(/\s+/g, ' ')
        .trim();
}
export function inferProfiles(cwd) {
    const rulesDir = join(cwd, '.cursor', 'rules');
    if (!existsSync(rulesDir))
        return [];
    return readdirSync(rulesDir)
        .filter((f) => f.endsWith('.mdc'))
        .map((f) => PROFILE_FILE_MAP[f])
        .filter((id) => !!id && ALL_PROFILES.some((p) => p.id === id));
}
const LEGACY_DIRS = ['.cursor/rules/skills'];
export function cleanLegacyDirs(cwd) {
    const removed = [];
    for (const rel of LEGACY_DIRS) {
        const abs = join(cwd, rel);
        if (existsSync(abs)) {
            rmSync(abs, { recursive: true, force: true });
            removed.push(rel);
        }
    }
    return removed;
}
//# sourceMappingURL=command-helpers.js.map