import { ti } from '../i18n/index.js';
import { hashProjectPath, specStore, knowledgeStore, globalStore } from '../storage/index.js';
import { getCurrentTier } from './license-gate.js';
import { checkLimits } from '../engine/license-validator.js';
import { inferDifficulty, calculateEstimation } from '../engine/estimator.js';
import { generateDiagrams } from '../engine/mermaid-generator.js';
import { analyzeSplit, formatSplitSuggestion } from '../engine/spec-splitter.js';
import { getScopeFilters, describeFilters, isExtendedChallenge } from '../engine/scope-filter.js';
import { generateHUContent } from './create-spec-hu.js';
import { buildAgentHuSection } from './create-spec/agent-spec-adapter.js';
import { isMcpSpec, buildMcpHuSection } from './create-spec/mcp-spec-adapter.js';
import { generateFichaTecnicaContent, detectContextFlags, checkConstitutionCompliance, } from './create-spec-tech.js';
import { writeFile, mkdir } from 'node:fs/promises';
import { join } from 'node:path';
import { detectContradictions } from '../engine/contradiction-detector.js';
import { detectTeamScale } from '../engine/platform-engineering/idp-detector.js';
import { runPreSpecDepCheck } from '../engine/dep-auditor/pre-spec-check.js';
import { generateProgressContent } from '../engine/progress-writer.js';
import { isLegacyLocation, getSpecFileNames } from '../engine/planu-config-writer.js';
import { generatePerSpecExecutiveReport, generatePerSpecTechnicalReport, } from '../engine/doc-generator/per-spec-report/index.js';
/**
 * Generate a URL-safe slug from a title.
 */
function slugify(text) {
    return text
        .toLowerCase()
        .normalize('NFD')
        .replace(/[\u0300-\u036f]/g, '') // remove diacritics
        .replace(/[^a-z0-9]+/g, '-')
        .replace(/^-+|-+$/g, '')
        .slice(0, 60);
}
/**
 * Generate the next spec ID based on existing specs count.
 */
function generateSpecId(existingCount) {
    const num = existingCount + 1;
    return `SPEC-${String(num).padStart(3, '0')}`;
}
/**
 * Generate a git branch name from the spec.
 */
function generateBranchName(specId, slug, type) {
    const prefix = {
        feature: 'feat',
        refactor: 'refactor',
        bugfix: 'fix',
        infra: 'infra',
        docs: 'docs',
        project: 'project',
    };
    return `${prefix[type] ?? 'feat'}/${specId.toLowerCase()}-${slug}`;
}
export async function handleCreateSpec(params) {
    const { title, description, projectPath, type = 'feature', scope = 'feature', target = 'fullstack', tags = [], feature, clarificationSessionId, } = params;
    try {
        const projectId = hashProjectPath(projectPath);
        // Load project knowledge (optional, but enriches the spec)
        const knowledge = await knowledgeStore.getKnowledge(projectId);
        // Load clarification session if provided
        const clarificationSession = clarificationSessionId
            ? await knowledgeStore.getClarification(projectId, clarificationSessionId)
            : null;
        // Get existing specs to generate next ID
        const existingSpecs = await specStore.listSpecs(projectId);
        // License: check active spec limit (exclude completed specs)
        const activeSpecs = existingSpecs.filter((s) => s.status !== 'done');
        const tier = await getCurrentTier();
        const specLimit = checkLimits(tier, activeSpecs.length, 'maxActiveSpecs');
        if (!specLimit.allowed) {
            return { content: [{ type: 'text', text: specLimit.message }], isError: true };
        }
        // Generate spec ID and slug
        const specId = generateSpecId(existingSpecs.length);
        const slug = slugify(title);
        // Check for duplicate title
        const duplicate = existingSpecs.find((s) => slugify(s.title) === slug);
        if (duplicate) {
            // Allow creation but warn
        }
        // Infer difficulty and calculate estimation
        const difficulty = inferDifficulty(type, scope);
        const globalConfig = await globalStore.getGlobalConfig();
        const estimation = calculateEstimation(type, scope, difficulty, globalConfig);
        // Determine risk level from difficulty and scope
        const risk = difficulty >= 4 || scope === 'architectural'
            ? 'high'
            : difficulty >= 3 || scope === 'cross-module'
                ? 'medium'
                : 'low';
        // Build spec location with naming convention detection
        const specLocation = knowledge?.specLocation ?? 'planu/specs';
        const naming = isLegacyLocation(specLocation) ? 'legacy' : 'modern';
        const fileNames = getSpecFileNames(naming);
        const featureSlug = feature ? slugify(feature) : '_general';
        const specDir = join(projectPath, specLocation, featureSlug, slug);
        const specPath = join(specDir, fileNames.spec);
        const technicalPath = join(specDir, fileNames.technical);
        const progressPath = join(specDir, fileNames.progress);
        // Generate git branch name
        const gitBranch = generateBranchName(specId, slug, type);
        // Build the Spec object
        const now = new Date().toISOString();
        const spec = {
            id: specId,
            title,
            slug,
            feature: featureSlug,
            type,
            scope,
            status: 'draft',
            difficulty,
            risk,
            projectId,
            createdAt: now,
            updatedAt: now,
            specPath,
            technicalPath,
            progressPath,
            estimation,
            actuals: null,
            target,
            tags,
            dependencies: [],
            blockedBy: [],
            gitBranch,
            impactAnalysis: null,
        };
        // Detect context flags for diagrams and filters
        const contextFlags = detectContextFlags(spec, knowledge);
        // Generate Mermaid diagrams
        const diagrams = generateDiagrams(spec, knowledge, contextFlags);
        // Analyze if spec should be split
        const splitSuggestion = analyzeSplit({
            criteriaCount: 4, // Default criteria for new specs
            moduleCount: scope === 'cross-module' ? 5 : scope === 'architectural' ? 6 : 2,
            estimatedHours: estimation.devHours,
            description,
            type,
            scope,
            target,
        }, specId);
        // Get scope filter configuration
        const scopeFilters = getScopeFilters(scope, {
            hasDatabase: contextFlags.hasDatabase,
            hasUi: contextFlags.hasUi,
        });
        // Validate spec against Constitution (strict violations block creation)
        const constitution = await knowledgeStore.getConstitution(projectId);
        let constitutionWarnings = [];
        if (constitution && constitution.principles.length > 0) {
            const violations = checkConstitutionCompliance(title, tags, constitution.principles);
            const strictViolations = violations.filter((v) => v.severity === 'error');
            if (strictViolations.length > 0) {
                return {
                    content: [
                        {
                            type: 'text',
                            text: JSON.stringify({
                                error: 'Constitution violation',
                                strictViolations,
                                message: `Spec violates ${strictViolations.length} strict Constitution principle(s). Revise the spec or update the Constitution.`,
                            }, null, 2),
                        },
                    ],
                    isError: true,
                };
            }
            constitutionWarnings = violations.filter((v) => v.severity === 'warning');
        }
        // Create spec directory and files
        await mkdir(specDir, { recursive: true });
        const agentSection = type === 'agent'
            ? buildAgentHuSection(title, description, knowledge, knowledge?.experienceLevel === 'beginner' ? 'beginner' : 'expert')
            : '';
        // SPEC-016b: MCP server spec section (tool definitions, resources, protocol compliance)
        const mcpSection = isMcpSpec(knowledge) ? buildMcpHuSection(title, description, knowledge) : '';
        // SPEC-048: Detect team scale for platform engineering sections
        const teamScale = knowledge?.projectPath
            ? await detectTeamScale(knowledge.projectPath)
            : undefined;
        // SPEC-025 tech debt: run pre-spec dep check to surface warnings in HU.md
        const depWarnings = knowledge?.projectPath && knowledge.projectPath.length > 0
            ? await runPreSpecDepCheck(knowledge.projectPath, knowledge)
            : undefined;
        const huContent = generateHUContent(spec, description, knowledge, undefined, teamScale, depWarnings) +
            agentSection +
            mcpSection;
        const fichaTecnicaContent = generateFichaTecnicaContent(spec, description, estimation, knowledge, diagrams, teamScale);
        await writeFile(specPath, huContent, 'utf-8');
        await writeFile(technicalPath, fichaTecnicaContent, 'utf-8');
        // Generate and write progress.md
        const progressContent = generateProgressContent(spec);
        await writeFile(progressPath, progressContent, 'utf-8');
        // Generate per-spec HTML reports
        const execReport = generatePerSpecExecutiveReport(spec, [], []);
        const techReport = generatePerSpecTechnicalReport(spec, diagrams, [], []);
        const execReportPath = join(specDir, 'executive-report.html');
        const techReportPath = join(specDir, 'technical-report.html');
        await writeFile(execReportPath, execReport.content, 'utf-8');
        await writeFile(techReportPath, techReport.content, 'utf-8');
        // Update spec with report paths
        spec.executiveReportPath = execReportPath;
        spec.technicalReportPath = techReportPath;
        // Persist spec in storage
        await specStore.createSpec(projectId, spec);
        // Brief contradiction check (non-blocking — warns but does not prevent creation)
        const allSpecs = await specStore.listSpecs(projectId);
        const contradictionHint = (() => {
            try {
                const specInputs = allSpecs.map((s) => ({
                    id: s.id,
                    title: s.title,
                    content: s.title + ' ' + description,
                }));
                const contradictions = detectContradictions(specInputs);
                const newSpecContradictions = contradictions.filter((c) => c.specA === specId || c.specB === specId);
                if (newSpecContradictions.length === 0) {
                    return undefined;
                }
                const blockers = newSpecContradictions.filter((c) => c.severity === 'blocker');
                return blockers.length > 0
                    ? `[CONFLICT] ${blockers.length} potential blocker contradiction(s) detected. Run detect_contradictions for details.`
                    : `[WARNING] ${newSpecContradictions.length} potential contradiction(s) detected. Run detect_contradictions for details.`;
            }
            catch {
                return undefined;
            }
        })();
        const result = {
            specId: spec.id,
            title: spec.title,
            slug: spec.slug,
            type: spec.type,
            scope: spec.scope,
            difficulty: spec.difficulty,
            risk: spec.risk,
            target: spec.target,
            status: spec.status,
            gitBranch: spec.gitBranch,
            specPath,
            technicalPath,
            progressPath,
            executiveReportPath: execReportPath,
            technicalReportPath: techReportPath,
            estimation: {
                devHours: estimation.devHours,
                reviewHours: estimation.reviewHours,
                totalCostUsd: estimation.totalCostUsd,
                recommendedModel: estimation.recommendedModel,
                executionMode: estimation.tokenOptimization.mode,
            },
            diagrams: diagrams.map((d) => ({ type: d.type, title: d.title })),
            scopeFilters: {
                filters: scopeFilters.filters,
                description: describeFilters(scopeFilters),
                extendedChallenge: isExtendedChallenge(scope),
            },
            duplicateWarning: duplicate ? ti('spec.duplicateTitle', { title, slug }) : undefined,
            ...(constitutionWarnings.length > 0 ? { constitutionWarnings } : {}),
            ...(clarificationSession
                ? {
                    linkedClarificationSession: clarificationSession.id,
                    clarificationTopic: clarificationSession.topic,
                    clarificationAnswersUsed: Object.keys(clarificationSession.answers).length,
                }
                : {
                    clarificationNote: 'Spec created directly from description — Planu inferred requirements from project context.',
                }),
            message: ti('tools.create_spec.success', { id: specId, title }),
            ...(contradictionHint ? { contradictionHint } : {}),
        };
        if (splitSuggestion) {
            const level = knowledge?.experienceLevel ?? 'intermediate';
            result.splitSuggestion = {
                shouldSplit: true,
                reason: splitSuggestion.reason,
                subSpecs: splitSuggestion.suggestedSpecs,
                formatted: formatSplitSuggestion(splitSuggestion, level === 'beginner' ? 'beginner' : 'expert'),
            };
        }
        return {
            content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
        };
    }
    catch (error) {
        const message = error instanceof Error ? error.message : String(error);
        return {
            content: [{ type: 'text', text: ti('errors.internalError', { message }) }],
            isError: true,
        };
    }
}
//# sourceMappingURL=create-spec.js.map