// src/core/spec-api.ts — Transport-agnostic spec creation and listing (SPEC-608)
import { mkdir } from 'node:fs/promises';
import { atomicWriteFile } from '../engine/safety/atomic-write-file.js';
import { join, resolve } from 'node:path';
import { randomUUID } from 'node:crypto';
import { hashProjectPath, specStore } from '../storage/index.js';
import { inferDifficulty, calculateEstimation } from '../engine/estimator.js';
import { generateLeanSpecContent } from '../engine/spec-format/lean-spec-generator.js';
import { generateLeanTechnicalContent } from '../engine/spec-format/lean-technical-generator.js';
import { buildUnifiedSpecContent } from '../engine/spec-format/unified-spec-builder.js';
function slugify(text) {
    return text
        .toLowerCase()
        .replace(/[^a-z0-9]+/g, '-')
        .replace(/^-|-$/g, '')
        .slice(0, 60);
}
function generateSpecId(existingSpecs) {
    const nums = existingSpecs
        .map((s) => parseInt(s.id.replace('SPEC-', ''), 10))
        .filter((n) => !Number.isNaN(n));
    const next = nums.length ? Math.max(...nums) + 1 : 1;
    return `SPEC-${String(next).padStart(3, '0')}`;
}
function generateBranchName(specId, slug, type) {
    const prefix = type === 'bugfix' ? 'fix' : type === 'refactor' ? 'refactor' : 'feat';
    return `${prefix}/${specId.toLowerCase()}-${slug}`;
}
/**
 * Transport-agnostic spec creation.
 * Returns typed domain results — callers (MCP, CLI, HTTP) handle their own formatting.
 */
export async function createSpec(input) {
    const projectPath = input.projectPath ?? process.cwd();
    const projectId = hashProjectPath(projectPath);
    const existingSpecs = await specStore.listSpecs(projectId);
    const specId = generateSpecId(existingSpecs);
    const slug = slugify(input.title);
    const type = input.type ?? 'feature';
    const scope = input.scope ?? 'feature';
    const target = input.target ?? 'backend';
    const gitBranch = generateBranchName(specId, slug, type);
    const difficulty = inferDifficulty(type, scope);
    const estimation = calculateEstimation(type, scope, difficulty);
    const specLocation = 'planu/specs';
    const specDir = resolve(join(projectPath, specLocation, `${specId}-${slug}`));
    const specPath = join(specDir, 'spec.md');
    const technicalPath = specPath;
    const now = new Date().toISOString();
    const spec = {
        id: specId,
        uuid: randomUUID(),
        title: input.title,
        slug,
        feature: input.feature,
        type,
        scope,
        status: 'draft',
        difficulty,
        risk: 'low',
        projectId,
        createdAt: now,
        updatedAt: now,
        specPath,
        technicalPath,
        estimation,
        actuals: null,
        target,
        tags: input.tags ?? [],
        dependencies: [],
        blockedBy: [],
        gitBranch,
        impactAnalysis: null,
    };
    const leanSpec = generateLeanSpecContent({
        spec,
        description: input.description,
        estimation,
        acFormat: input.acFormat,
    });
    const leanTechnical = generateLeanTechnicalContent({
        specId,
        filesToCreate: [],
        filesToModify: [],
    });
    // SPEC-709: write unified spec.md (technical content embedded as `## Technical` section)
    const unified = buildUnifiedSpecContent(leanSpec, leanTechnical);
    await mkdir(specDir, { recursive: true });
    await atomicWriteFile(specPath, unified);
    await specStore.createSpec(projectId, spec);
    return {
        specId,
        specPath,
        technicalPath,
        diagrams: [],
        message: `Spec ${specId} created: ${input.title}`,
    };
}
/** List all specs for a project. Returns domain types, no MCP SDK required. */
export async function listSpecs(projectPath) {
    const path = projectPath ?? process.cwd();
    const projectId = hashProjectPath(path);
    return specStore.listSpecs(projectId);
}
//# sourceMappingURL=spec-api.js.map