"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.createPhaseWorkspace = createPhaseWorkspace;
const node_fs_1 = __importDefault(require("node:fs"));
const node_path_1 = __importDefault(require("node:path"));
const errors_1 = require("../errors");
const command_write_summary_1 = require("../license/command-write-summary");
const paths_1 = require("../paths");
const authoring_policy_1 = require("./authoring-policy");
const front_matter_utils_1 = require("./front-matter-utils");
const governed_hierarchy_context_1 = require("./governed-hierarchy-context");
const runtime_acceptance_1 = require("./runtime-acceptance");
const scaffold_application_1 = require("./scaffold-application");
const upstream_specs_1 = require("./upstream-specs");
const workflow_provenance_1 = require("./workflow-provenance");
const scaffold_target_path_policy_1 = require("./scaffold-target-path-policy");
const ALLOWED_PLANNING_DEPTH_VALUES = new Set(['standard', 'strict']);
const PHASE_TITLE_MINOR_WORDS = new Set([
    'a',
    'an',
    'and',
    'at',
    'by',
    'for',
    'from',
    'in',
    'of',
    'on',
    'or',
    'the',
    'to',
    'with',
]);
const PHASE_TITLE_ACRONYMS = new Map([
    ['ai', 'AI'],
    ['api', 'API'],
    ['cli', 'CLI'],
    ['css', 'CSS'],
    ['html', 'HTML'],
    ['id', 'ID'],
    ['ids', 'IDs'],
    ['json', 'JSON'],
    ['sdk', 'SDK'],
    ['ui', 'UI'],
    ['url', 'URL'],
    ['urls', 'URLs'],
    ['ux', 'UX'],
    ['yaml', 'YAML'],
]);
function createPhaseWorkspace(repositoryRoot, options) {
    const runtimeEvidencePathPolicy = (0, scaffold_target_path_policy_1.readPlanningScaffoldTargetPathPolicy)(repositoryRoot);
    const sliceOverviewPath = resolveSliceOverviewPath(repositoryRoot, options.sliceOverviewPath);
    if (!node_fs_1.default.existsSync(sliceOverviewPath.absolute)) {
        throw (0, errors_1.createUsageError)(`Parent slice overview not found at '${sliceOverviewPath.relative}'.`, [
            'Run day-shift slice new first or pass the correct --slice-overview path.',
        ]);
    }
    const parsedSliceOverview = parseSliceOverview(sliceOverviewPath.absolute);
    (0, governed_hierarchy_context_1.assertCanonicalGovernedParentSync)(repositoryRoot, {
        layer: 'slice',
        parentPath: sliceOverviewPath.relative,
        slice: parsedSliceOverview.slice,
        policy: parsedSliceOverview.governedPolicy,
    });
    const sliceOverviewText = node_fs_1.default.readFileSync(sliceOverviewPath.absolute, 'utf8');
    const declaredPhaseSlugs = (0, authoring_policy_1.declaredPlanningChildSlugs)(sliceOverviewText, 'Phases');
    const decompositionIssues = (0, authoring_policy_1.auditParentDecomposition)({
        artifactPath: sliceOverviewPath.relative,
        markdownText: sliceOverviewText,
        childKind: 'phase',
        declaredChildSlugs: declaredPhaseSlugs,
    });
    if (decompositionIssues.length > 0) {
        throw (0, errors_1.createUsageError)(`Planning decomposition contract rejected '${sliceOverviewPath.relative}' before phase writes.`, (0, authoring_policy_1.formatParentDecompositionIssues)(decompositionIssues));
    }
    const upstreamSpecs = (0, upstream_specs_1.normalizeUpstreamSpecsToLocalSpecPaths)(repositoryRoot, parsedSliceOverview.upstreamSpecs);
    const phaseSlug = resolvePhaseSlug(options.phaseSlug);
    if (!declaredPhaseSlugs.includes(phaseSlug)) {
        throw (0, errors_1.createUsageError)(`Phase '${phaseSlug}' is not declared by '${sliceOverviewPath.relative}'.`, [
            'Declare the phase and update the authored target count and decomposition rationale before scaffolding.',
        ]);
    }
    const authoredScaffoldEvidence = (0, authoring_policy_1.inspectChildScaffoldEvidence)({
        markdownText: sliceOverviewText,
        childKind: 'phase',
        childSlug: phaseSlug,
        declaredChildSlugs: declaredPhaseSlugs,
        runtimeEvidencePathPolicy,
    });
    const phaseTitle = resolvePhaseTitle(phaseSlug, options.phaseTitle);
    const sliceDirectoryPath = node_path_1.default.dirname(sliceOverviewPath.absolute);
    const phasesDirectoryPath = node_path_1.default.join(sliceDirectoryPath, 'phases');
    const phaseDirectoryPath = node_path_1.default.join(phasesDirectoryPath, phaseSlug);
    const phaseDirectoryRelative = (0, front_matter_utils_1.toRepositoryLikePath)(node_path_1.default.relative(repositoryRoot, phaseDirectoryPath));
    const overviewRelativePath = (0, paths_1.composeCanonicalPlanningOverviewPath)('phase', phaseDirectoryRelative);
    const overviewPath = node_path_1.default.join(repositoryRoot, overviewRelativePath);
    const scaffoldEvidence = (0, authoring_policy_1.projectPlanningScaffoldEvidence)(authoredScaffoldEvidence, {
        ownership: [`Phase '${phaseSlug}' planning workspace declared by '${sliceOverviewPath.relative}'.`],
        dependencies: [sliceOverviewPath.relative],
        targetPaths: [overviewRelativePath],
        adapterPaths: ['src/cli/commands/phase-new/index.ts'],
        validationCommands: [`node dist/cli/index.js validation smoke --scope planning --artifact ${overviewRelativePath}`],
        rollback: [`Remove the newly created '${overviewRelativePath}' if scaffold validation fails.`],
    });
    assertExecutableScaffoldEvidence(sliceOverviewPath.relative, scaffoldEvidence);
    const renderedOverview = node_fs_1.default.existsSync(overviewPath)
        ? null
        : renderPhaseOverviewMarkdown({
            phaseTitle,
            slice: parsedSliceOverview.slice,
            phaseSlug,
            planningDepth: parsedSliceOverview.planningDepth,
            sliceOverviewPath: sliceOverviewPath.relative,
            upstreamSpecs,
            governedPolicy: parsedSliceOverview.governedPolicy,
            runtimeAcceptance: parsedSliceOverview.runtimeAcceptance === null
                ? null
                : (0, runtime_acceptance_1.childRuntimeAcceptanceMetadata)(parsedSliceOverview.runtimeAcceptance),
            scaffoldEvidence,
            workflowCliCommand: options.workflowCliCommand,
        });
    const overviewExists = node_fs_1.default.existsSync(overviewPath);
    if (overviewExists) {
        (0, governed_hierarchy_context_1.assertExistingGovernedArtifactSync)(overviewPath, {
            artifactType: 'phase_overview',
            slice: parsedSliceOverview.slice,
            phase: phaseSlug,
            planningDepth: parsedSliceOverview.planningDepth,
            upstream: { slice_overview: sliceOverviewPath.relative },
        });
    }
    const phasesDirectoryAction = node_fs_1.default.existsSync(phasesDirectoryPath) ? 'kept' : 'created';
    const plannedWrites = !overviewExists && renderedOverview !== null ? [{ path: overviewRelativePath, contents: renderedOverview }] : [];
    const overviewText = overviewExists ? node_fs_1.default.readFileSync(overviewPath, 'utf8') : (renderedOverview ?? '');
    const declaredMilestoneSlugs = (0, authoring_policy_1.declaredPlanningChildSlugs)(overviewText, 'Milestones');
    const refinementIssues = (0, authoring_policy_1.auditParentDecomposition)({
        artifactPath: overviewRelativePath,
        markdownText: overviewText,
        childKind: 'milestone',
        declaredChildSlugs: declaredMilestoneSlugs,
    });
    let application = {
        outcome: 'no-write',
        intendedPaths: [],
        changedPaths: [],
        transactionId: null,
        conflicts: [],
        recoveryPath: null,
        failure: null,
    };
    if (options.validateOnly !== true) {
        application = (0, scaffold_application_1.applyPlanningScaffoldSync)(repositoryRoot, plannedWrites, {
            parentPaths: [sliceOverviewPath.relative],
        });
        (0, scaffold_application_1.assertPlanningScaffoldApplied)(application);
    }
    return {
        repositoryRoot,
        slice: parsedSliceOverview.slice,
        planningDepth: parsedSliceOverview.planningDepth,
        sliceOverviewPath: sliceOverviewPath.relative,
        phasesDirectoryPath,
        phaseDirectoryPath,
        overviewPath,
        phaseSlug,
        phaseTitle,
        phasesDirectoryAction,
        overviewAction: overviewExists ? 'kept' : 'created',
        contributingSpecIds: upstreamSpecs.map((entry) => entry.id),
        plannedWrites,
        requiresRefinement: refinementIssues.length > 0,
        refinementIssues,
        scaffoldEvidence,
        application,
        commandWriteSummary: (0, command_write_summary_1.normalizeCommandWriteSummary)({
            commandFamily: 'phase_generation',
            primaryOutputArtifacts: [(0, front_matter_utils_1.toRepositoryLikePath)(node_path_1.default.relative(repositoryRoot, overviewPath))],
            updatedArtifacts: [
                {
                    path: (0, front_matter_utils_1.toRepositoryLikePath)(node_path_1.default.relative(repositoryRoot, overviewPath)),
                    action: overviewExists ? 'kept' : 'created',
                    reason: overviewExists ? 'no_write' : 'accepted_create',
                },
            ],
        }),
    };
}
function resolveSliceOverviewPath(repositoryRoot, inputPath) {
    try {
        return (0, paths_1.resolvePlanningOverviewInputPath)(repositoryRoot, {
            layer: 'slice',
            inputPath,
        });
    }
    catch (error) {
        throw (0, errors_1.createUsageError)(`Invalid --slice-overview path '${inputPath}'.`, [
            error instanceof Error ? error.message : String(error),
        ]);
    }
}
function resolvePhaseSlug(rawPhaseSlug) {
    if ((0, paths_1.isCanonicalSlug)(rawPhaseSlug)) {
        return rawPhaseSlug;
    }
    const normalized = (0, paths_1.normalizeCanonicalSlug)(rawPhaseSlug);
    if (normalized.kind === 'canonical-slug') {
        return normalized.normalizedSlug;
    }
    throw (0, errors_1.createUsageError)(`Invalid phase slug '${rawPhaseSlug}'.`, [normalized.reason.message]);
}
function resolvePhaseTitle(phaseSlug, requestedTitle) {
    const trimmed = requestedTitle?.trim();
    if (trimmed !== undefined && trimmed !== '') {
        return trimmed;
    }
    const words = phaseSlug
        .replace(/^\d{2}-/u, '')
        .split('-')
        .filter((word) => word !== '');
    return words
        .map((word, index) => {
        const normalizedWord = word.toLowerCase();
        const acronym = PHASE_TITLE_ACRONYMS.get(normalizedWord);
        if (acronym !== undefined) {
            return acronym;
        }
        if (index > 0 && PHASE_TITLE_MINOR_WORDS.has(normalizedWord)) {
            return normalizedWord;
        }
        return normalizedWord.charAt(0).toUpperCase() + normalizedWord.slice(1);
    })
        .join(' ');
}
function parseSliceOverview(sliceOverviewPath) {
    const fileText = node_fs_1.default.readFileSync(sliceOverviewPath, 'utf8');
    const frontMatter = extractFrontMatter(sliceOverviewPath, fileText);
    const artifactType = readTopLevelField(frontMatter.lines, 'artifact_type');
    if (artifactType !== 'slice_overview') {
        throw (0, errors_1.createUsageError)(`Parent overview '${(0, front_matter_utils_1.toRepositoryLikePath)(sliceOverviewPath)}' must use artifact_type: slice_overview.`);
    }
    const slice = readTopLevelField(frontMatter.lines, 'slice');
    if (slice === undefined || slice.trim() === '') {
        throw (0, errors_1.createUsageError)(`Parent overview '${(0, front_matter_utils_1.toRepositoryLikePath)(sliceOverviewPath)}' is missing required top-level field 'slice'.`);
    }
    const planningDepth = readTopLevelField(frontMatter.lines, 'planning_depth')?.trim() || 'standard';
    const upstreamSpecs = parseUpstreamSpecs(frontMatter.lines, sliceOverviewPath);
    const runtimeAcceptance = (0, runtime_acceptance_1.assertRuntimeAcceptanceInspection)((0, runtime_acceptance_1.inspectRuntimeAcceptance)({
        artifactPath: sliceOverviewPath,
        artifactKind: 'slice',
        frontMatterLines: frontMatter.lines,
        markdownText: fileText,
    }));
    const governedPolicy = (0, governed_hierarchy_context_1.readGovernedHierarchyPolicy)(frontMatter.lines);
    if (upstreamSpecs.length === 0) {
        throw (0, errors_1.createUsageError)(`Parent overview '${(0, front_matter_utils_1.toRepositoryLikePath)(sliceOverviewPath)}' must include at least one upstream spec entry under upstream.specs.`);
    }
    return {
        slice: slice.trim(),
        planningDepth,
        upstreamSpecs,
        runtimeAcceptance,
        governedPolicy,
    };
}
function extractFrontMatter(filePath, text) {
    const lines = text.split(/\r?\n/);
    if (lines[0] !== '---') {
        throw (0, errors_1.createUsageError)(`Parent overview '${(0, front_matter_utils_1.toRepositoryLikePath)(filePath)}' is missing YAML front matter.`);
    }
    let closingIndex = -1;
    for (let index = 1; index < lines.length; index += 1) {
        if (lines[index] === '---') {
            closingIndex = index;
            break;
        }
    }
    if (closingIndex === -1) {
        throw (0, errors_1.createUsageError)(`Parent overview '${(0, front_matter_utils_1.toRepositoryLikePath)(filePath)}' has malformed YAML front matter.`);
    }
    return {
        lines: lines.slice(1, closingIndex),
    };
}
function readTopLevelField(lines, key) {
    for (const line of lines) {
        if (/^\s/.test(line)) {
            continue;
        }
        const match = line.match(/^([A-Za-z0-9_]+):\s*(.*)$/);
        if (match === null) {
            continue;
        }
        if (match[1] === key) {
            return (0, front_matter_utils_1.parseScalar)(match[2]);
        }
    }
    return undefined;
}
function parseUpstreamSpecs(lines, filePath) {
    const entries = [];
    for (let index = 0; index < lines.length; index += 1) {
        const idMatch = lines[index].match(/^\s*-\s+id:\s*(.+)$/);
        if (idMatch === null) {
            continue;
        }
        const depthLine = lines[index + 1];
        const refLine = lines[index + 2];
        const sourceTypeLine = lines[index + 3];
        const depthMatch = depthLine?.match(/^\s+depth:\s*(.+)$/);
        const refMatch = refLine?.match(/^\s+ref:\s*(.+)$/);
        const sourceTypeMatch = sourceTypeLine?.match(/^\s+source_type:\s*(.+)$/);
        if (depthMatch === null || refMatch === null || sourceTypeMatch === null) {
            throw (0, errors_1.createUsageError)(`Parent overview '${(0, front_matter_utils_1.toRepositoryLikePath)(filePath)}' has malformed upstream.specs metadata near '${lines[index].trim()}'.`);
        }
        entries.push({
            id: (0, front_matter_utils_1.parseScalar)(idMatch[1]),
            depth: (0, front_matter_utils_1.parseScalar)(depthMatch[1]),
            ref: (0, front_matter_utils_1.parseScalar)(refMatch[1]),
            sourceType: (0, front_matter_utils_1.parseScalar)(sourceTypeMatch[1]),
        });
        index += 3;
    }
    return entries;
}
function renderPhaseOverviewMarkdown(options) {
    const workflowProvenance = (0, workflow_provenance_1.buildCliWorkflowProvenance)(options.workflowCliCommand ??
        `day-shift phase new --slice-overview ${options.sliceOverviewPath} --phase-slug ${options.phaseSlug}`);
    const upstreamSpecs = options.upstreamSpecs
        .map((entry) => {
        return [
            `    - id: ${entry.id}`,
            `      depth: ${entry.depth}`,
            `      ref: ${JSON.stringify(entry.ref)}`,
            `      source_type: ${JSON.stringify(entry.sourceType)}`,
        ].join('\n');
    })
        .join('\n');
    const text = (0, runtime_acceptance_1.injectRuntimeAcceptanceFrontMatter)([
        '---',
        'artifact_schema_version: 1',
        'artifact_type: phase_overview',
        `slice: ${options.slice}`,
        `phase: ${options.phaseSlug}`,
        `planning_depth: ${options.planningDepth}`,
        ...(0, governed_hierarchy_context_1.renderGovernedHierarchyPolicyLines)(options.governedPolicy),
        `workflow_provenance: ${workflowProvenance.workflowProvenance}`,
        `workflow_cli_command: ${JSON.stringify(workflowProvenance.workflowCliCommand)}`,
        'status: draft',
        'upstream:',
        '  specs:',
        upstreamSpecs,
        `  slice_overview: ${options.sliceOverviewPath}`,
        '---',
        '',
        `# ${options.phaseTitle}`,
        '',
        '## Purpose',
        '',
        `Document the ${options.phaseSlug} phase checkpoint from the selected slice context so milestone planning can proceed with deterministic traceability.`,
        '',
        '## Scope',
        '',
        '- Preserve deterministic phase-level planning paths beneath the selected slice overview.',
        '- Keep parent and source traceability explicit in phase metadata.',
        '- Keep phase content focused on outcome scope rather than task implementation detail.',
        '',
        '## Navigation',
        '',
        `- ${options.sliceOverviewPath}`,
        '',
        '## Milestones',
        '',
        '- Replace with `01-some-ordered-slug`: short milestone description before creating milestone artifacts.',
        '',
        '## Acceptance Criteria',
        '',
        '- The phase documents clear milestone checkpoints for this planning slice.',
        '- Phase-level scope remains aligned with parent slice intent.',
        '',
        '## Dependencies',
        '',
        '- Parent slice overview and upstream spec context.',
        '',
        '## Risks',
        '',
        '- Follow-on updates should keep phase-generation guidance and executable behavior aligned.',
        '',
        '## Validation Focus',
        '',
        ...options.scaffoldEvidence.validationCommands.map((entry) => `- \`${entry}\``),
        '',
        '## Implementation Target Paths',
        '',
        ...options.scaffoldEvidence.targetPaths.map((entry) => `- ${entry}`),
        '',
        '## Validation Commands',
        '',
        '```sh',
        ...options.scaffoldEvidence.validationCommands,
        '```',
        '',
        '## Rollback / Recovery',
        '',
        ...options.scaffoldEvidence.rollback.map((entry) => `- ${entry}`),
        '',
        '## Scaffold Evidence',
        '',
        ...renderScaffoldEvidenceLines(options.scaffoldEvidence),
        '',
        '## Open Questions',
        '',
        '- None currently.',
        '',
    ].join('\n'), options.runtimeAcceptance);
    assertPlanningAuthoringCompliance('phase_overview', text);
    try {
        if (!ALLOWED_PLANNING_DEPTH_VALUES.has(options.planningDepth)) {
            throw new TypeError(`Unsupported planning_depth token '${options.planningDepth}' for field 'planning_depth'.`);
        }
        return (0, front_matter_utils_1.applyStatusAndPlanningFieldTransition)(text, {
            slice: options.slice,
            phase: options.phaseSlug,
            planning_depth: options.planningDepth,
            status: 'draft',
        });
    }
    catch (error) {
        if (error instanceof TypeError) {
            throw (0, errors_1.createInvalidConfigError)('Phase overview metadata updates were rejected.', [error.message], [
                {
                    code: 'PHASE_METADATA_UPDATE_BLOCKED',
                    message: error.message,
                    severity: 'error',
                },
            ]);
        }
        throw error;
    }
}
function assertExecutableScaffoldEvidence(parentPath, evidence) {
    if (evidence.complete)
        return;
    throw (0, errors_1.createInvalidConfigError)(`Planning scaffold refinement is required before phase '${evidence.childSlug}' can be created.`, [
        ...evidence.missingEvidence.map((kind) => `${parentPath}: phase '${evidence.childSlug}' is missing ${kind} evidence required for an executable scaffold.`),
        'No phase artifact write was attempted.',
    ], evidence.missingEvidence.map((kind) => ({
        code: `PLANNING_SCAFFOLD_${kind.toUpperCase()}_EVIDENCE_MISSING`,
        message: `Phase '${evidence.childSlug}' is missing ${kind} evidence required for an executable scaffold.`,
        severity: 'error',
        path: parentPath,
        evidence: {
            category: 'planning-review',
            details: {
                childKind: evidence.childKind,
                childSlug: evidence.childSlug,
                missingEvidenceKind: kind,
                noWriteRequired: true,
            },
        },
    })));
}
function renderScaffoldEvidenceLines(evidence) {
    return [
        ...evidence.ownership.map((entry) => `- ownership: ${entry}`),
        ...evidence.dependencies.map((entry) => `- dependency: ${entry}`),
        ...evidence.targetPaths.map((entry) => `- target: ${entry}`),
        ...evidence.adapterPaths.map((entry) => `- adapter: ${entry}`),
        ...evidence.validationCommands.map((entry) => `- validation: ${entry}`),
        ...evidence.rollback.map((entry) => `- rollback: ${entry}`),
    ];
}
function assertPlanningAuthoringCompliance(artifactType, markdownText) {
    const issues = (0, authoring_policy_1.auditPlanningArtifactAuthoring)({
        artifactPath: 'generated phase overview',
        artifactType,
        markdownText,
    });
    if (issues.length > 0) {
        throw (0, errors_1.createUsageError)(`Planning authoring policy rejected generated ${artifactType} scaffold text.`, (0, authoring_policy_1.formatPlanningAuthoringIssues)(issues));
    }
}
