"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.createSliceWorkspace = createSliceWorkspace;
const node_fs_1 = __importDefault(require("node:fs"));
const node_path_1 = __importDefault(require("node:path"));
const errors_1 = require("../errors");
const authoring_policy_1 = require("./authoring-policy");
const command_write_summary_1 = require("../license/command-write-summary");
const paths_1 = require("../paths");
const front_matter_utils_1 = require("./front-matter-utils");
const workflow_provenance_1 = require("./workflow-provenance");
const spec_registry_1 = require("../spec-registry");
const upstream_specs_1 = require("./upstream-specs");
function createSliceWorkspace(repositoryRoot, selection) {
    assertSelection(selection);
    const specIndexPath = node_path_1.default.join(repositoryRoot, ".day-shift", "specs", "index.json");
    const specIndex = parseSliceSpecIndex(node_fs_1.default.readFileSync(specIndexPath, "utf8"));
    const resolved = resolveSelection(specIndex.entries, selection);
    const implementationOrder = resolveImplementationOrder(resolved.contributors);
    const sliceSlug = resolveSliceSlug({
        implementationOrder,
        selected: resolved.selected,
        selectedSliceId: resolved.selectedSliceId
    });
    const orderedSlugResult = (0, paths_1.composeOrderedSlugName)(implementationOrder, sliceSlug);
    if (orderedSlugResult.kind !== "ordered-slug-name") {
        throw (0, errors_1.createUsageError)("Could not compose ordered slice directory name from selected spec context.", [orderedSlugResult.reason.message]);
    }
    const orderedSliceDirectoryName = orderedSlugResult.orderedSlugName;
    const sliceDirectoryPath = node_path_1.default.join(repositoryRoot, ".day-shift", "planning", orderedSliceDirectoryName);
    const overviewRelativePath = (0, paths_1.composeCanonicalPlanningOverviewPath)("slice", (0, front_matter_utils_1.toRepositoryLikePath)(node_path_1.default.relative(repositoryRoot, sliceDirectoryPath)));
    const overviewPath = node_path_1.default.join(repositoryRoot, overviewRelativePath);
    const decisionsDirectoryPath = node_path_1.default.join(sliceDirectoryPath, "decisions");
    const notesDirectoryPath = node_path_1.default.join(sliceDirectoryPath, "notes");
    const decisionsGitkeepPath = node_path_1.default.join(decisionsDirectoryPath, ".gitkeep");
    const notesGitkeepPath = node_path_1.default.join(notesDirectoryPath, ".gitkeep");
    const overviewExists = node_fs_1.default.existsSync(overviewPath);
    const overviewText = overviewExists
        ? null
        : renderSliceOverviewMarkdown({
            sliceSlug,
            contributors: resolved.contributors,
            implementationOrder,
            selectedSelector: selection.specId?.trim() !== ""
                ? `day-shift slice new --spec-id ${resolved.selected.id}`
                : `day-shift slice new --slice-id ${resolved.selectedSliceId}`
        });
    node_fs_1.default.mkdirSync(decisionsDirectoryPath, { recursive: true });
    node_fs_1.default.mkdirSync(notesDirectoryPath, { recursive: true });
    const decisionsGitkeepAction = writeGitkeep(decisionsGitkeepPath);
    const notesGitkeepAction = writeGitkeep(notesGitkeepPath);
    if (!overviewExists && overviewText !== null) {
        node_fs_1.default.writeFileSync(overviewPath, overviewText, "utf8");
    }
    return {
        repositoryRoot,
        specIndexPath,
        implementationOrder,
        sliceSlug,
        orderedSliceDirectoryName,
        sliceDirectoryPath,
        overviewPath,
        decisionsGitkeepPath,
        notesGitkeepPath,
        selectedSpecId: resolved.selected.id,
        selectedSliceId: resolved.selectedSliceId,
        contributingSpecIds: resolved.contributors.map((entry) => entry.id),
        overviewAction: overviewExists ? "kept" : "created",
        decisionsGitkeepAction,
        notesGitkeepAction,
        commandWriteSummary: (0, command_write_summary_1.normalizeCommandWriteSummary)({
            commandFamily: "slice_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 assertSelection(selection) {
    const hasSpecId = typeof selection.specId === "string" && selection.specId.trim() !== "";
    const hasSliceId = typeof selection.sliceId === "string" && selection.sliceId.trim() !== "";
    if (hasSpecId && hasSliceId) {
        throw (0, errors_1.createUsageError)("Provide either --spec-id or --slice-id, not both.");
    }
    if (!hasSpecId && !hasSliceId) {
        throw (0, errors_1.createUsageError)("Provide selection context via --spec-id or --slice-id.", ["Example: day-shift slice new --spec-id planning-artifacts-artifact-model"]);
    }
}
function resolveSelection(entries, selection) {
    if (selection.specId !== undefined && selection.specId.trim() !== "") {
        const selected = entries.find((entry) => entry.id === selection.specId?.trim());
        if (selected === undefined) {
            throw (0, errors_1.createUsageError)(`Unknown spec id '${selection.specId}'.`);
        }
        const selectedSliceId = resolveSelectedSliceId(selected);
        if (selected.optional.linked_slice !== undefined) {
            const contributors = entries.filter((entry) => {
                const linked = entry.optional.linked_slice;
                return linked !== undefined && linked.slice === selected.optional.linked_slice?.slice;
            });
            return {
                selected,
                selectedSliceId,
                contributors: contributors.length > 0 ? contributors : [selected]
            };
        }
        return {
            selected,
            selectedSliceId,
            contributors: [selected]
        };
    }
    const requestedSliceId = selection.sliceId?.trim() ?? "";
    const contributors = entries.filter((entry) => entry.optional.linked_slice?.slice === requestedSliceId);
    if (contributors.length === 0) {
        throw (0, errors_1.createUsageError)(`No registered specs found for slice '${requestedSliceId}'.`, ["When using --slice-id, the value must match linked_slice.slice in .day-shift/specs/index.json."]);
    }
    return {
        selected: contributors[0],
        selectedSliceId: requestedSliceId,
        contributors
    };
}
function resolveSelectedSliceId(entry) {
    if (entry.optional.linked_slice !== undefined) {
        return entry.optional.linked_slice.slice;
    }
    const destinationHead = entry.destination.split("/")[0];
    const normalized = (0, paths_1.normalizeCanonicalSlug)(destinationHead);
    if (normalized.kind === "canonical-slug") {
        return normalized.normalizedSlug;
    }
    throw (0, errors_1.createUsageError)(`Spec '${entry.id}' does not have linked_slice metadata and destination '${entry.destination}' cannot be normalized into a canonical slice slug.`, [normalized.reason.message]);
}
function resolveImplementationOrder(entries) {
    const orders = new Set();
    for (const entry of entries) {
        const value = entry.optional.implementation_order;
        if (typeof value === "string" && value.trim() !== "") {
            orders.add(value.trim());
            continue;
        }
        if (typeof value === "number" && Number.isFinite(value)) {
            orders.add(String(value));
        }
    }
    if (orders.size === 0) {
        throw (0, errors_1.createUsageError)("Selected slice context has no registered implementation_order metadata.", ["Set implementation_order in .day-shift/specs/index.json for the selected slice contributors."]);
    }
    if (orders.size > 1) {
        throw (0, errors_1.createUsageError)("Selected slice context has conflicting implementation_order values.", [...orders].map((value) => `implementation_order: ${value}`));
    }
    const [order] = [...orders];
    if (!(0, paths_1.isCanonicalSlug)(order)) {
        throw (0, errors_1.createUsageError)(`implementation_order '${order}' is not a canonical ordered prefix.`, ["Use lowercase letters, numbers, and hyphen-separated segments only."]);
    }
    return order;
}
function resolveSliceSlug(options) {
    const emergentSliceSlug = resolveDedicatedEmergentSliceSlug(options);
    if (emergentSliceSlug !== null) {
        return emergentSliceSlug;
    }
    const linkedPath = options.selected.optional.linked_slice?.path;
    if (typeof linkedPath === "string" && linkedPath !== "") {
        const linkedPathValue = (0, paths_1.parseRepositoryRelativePath)(linkedPath);
        const parts = linkedPathValue.normalizedPath.split("/");
        if (parts.length >= 4) {
            const directory = parts[2];
            const prefix = `${options.implementationOrder}-`;
            if (directory.startsWith(prefix)) {
                const candidate = directory.slice(prefix.length);
                if ((0, paths_1.isCanonicalSlug)(candidate)) {
                    return candidate;
                }
            }
        }
    }
    if ((0, paths_1.isCanonicalSlug)(options.selectedSliceId)) {
        return options.selectedSliceId;
    }
    const normalized = (0, paths_1.normalizeCanonicalSlug)(options.selectedSliceId);
    if (normalized.kind === "canonical-slug") {
        return normalized.normalizedSlug;
    }
    throw (0, errors_1.createUsageError)(`Selected slice id '${options.selectedSliceId}' cannot be used as a canonical slice slug.`, [normalized.reason.message]);
}
function parseSliceSpecIndex(contents) {
    try {
        return (0, spec_registry_1.parseSpecIndexDocumentText)(contents);
    }
    catch (error) {
        throw (0, errors_1.createUsageError)("Could not parse spec registry for slice selection.", [error instanceof Error ? error.message : String(error)]);
    }
}
function resolveDedicatedEmergentSliceSlug(options) {
    if (options.implementationOrder !== "00") {
        return null;
    }
    if (!options.selected.destination.startsWith("emergent/")) {
        return null;
    }
    const specPathValue = (0, paths_1.parseRepositoryRelativePath)(options.selected.spec_path);
    const isActiveEmergentSpec = specPathValue.segments[0] === ".day-shift" &&
        specPathValue.segments[1] === "specs" &&
        specPathValue.segments[2] === "00-emergent";
    if (!isActiveEmergentSpec) {
        return null;
    }
    const destinationSlug = options.selected.destination.slice("emergent/".length);
    if (!(0, paths_1.isCanonicalSlug)(destinationSlug)) {
        throw (0, errors_1.createUsageError)(`Emergent destination '${options.selected.destination}' cannot be used as a canonical slice slug.`, ["Use destination: emergent/<slug> with lowercase letters, numbers, and hyphen-separated segments."]);
    }
    return `emergent-${destinationSlug}`;
}
function writeGitkeep(filePath) {
    if (node_fs_1.default.existsSync(filePath)) {
        return "kept";
    }
    node_fs_1.default.writeFileSync(filePath, "", "utf8");
    return "created";
}
function renderSliceOverviewMarkdown(options) {
    const title = (0, front_matter_utils_1.toTitleCase)(options.sliceSlug);
    const workflowProvenance = (0, workflow_provenance_1.buildCliWorkflowProvenance)(options.selectedSelector);
    const sourcePaths = options.contributors.map((entry) => `- ${entry.spec_path}`).join("\n");
    const contributorList = options.contributors.map((entry) => `- ${entry.id}`).join("\n");
    const upstreamSpecs = options.contributors
        .map((entry) => {
        const upstreamEntry = (0, upstream_specs_1.createUpstreamSpecEntryFromSpecIndex)(entry);
        return [
            `    - id: ${upstreamEntry.id}`,
            `      depth: ${upstreamEntry.depth}`,
            `      ref: ${JSON.stringify(upstreamEntry.ref)}`,
            `      source_type: ${JSON.stringify(upstreamEntry.sourceType)}`
        ].join("\n");
    })
        .join("\n");
    const text = [
        "---",
        "artifact_schema_version: 1",
        "artifact_type: slice_overview",
        `slice: ${options.sliceSlug}`,
        `planning_depth: ${options.contributors[0].depth}`,
        `workflow_provenance: ${workflowProvenance.workflowProvenance}`,
        `workflow_cli_command: ${JSON.stringify(workflowProvenance.workflowCliCommand)}`,
        "status: draft",
        "upstream:",
        "  specs:",
        upstreamSpecs,
        "---",
        "",
        `# ${title}`,
        "",
        "## Purpose",
        "",
        `Document the ${options.sliceSlug} planning slice from registered spec context so downstream phase and milestone planning can proceed consistently.`,
        "",
        "## Source Specification",
        "",
        "This slice overview is derived from:",
        sourcePaths,
        "",
        "## Desired Outcome",
        "",
        `A stable planning root exists at .day-shift/planning/${options.implementationOrder}-${options.sliceSlug}/ with deterministic slice-level traceability.`,
        "",
        "## Scope",
        "",
        "- Preserve one ordered planning root for the selected slice context.",
        "- Preserve list-based upstream traceability for all contributing source specs.",
        "- Keep slice-level structure ready for phase planning.",
        "",
        "## Non-Goals",
        "",
        "- Implement phase, milestone, or task artifacts during slice generation.",
        "- Expand to undeclared child artifacts.",
        "",
        "## Planning Depth",
        "",
        options.contributors[0].depth,
        "",
        "## Phases",
        "",
        "- To be planned.",
        "",
        "## Decisions",
        "",
        "- This slice was generated from registered spec context.",
        "- Contributing specs:",
        contributorList,
        "",
        "## Risks",
        "",
        "- Follow-on updates should keep slice-generation guidance and executable behavior aligned.",
        "",
        "## Validation Strategy",
        "",
        "- Validate metadata and path contracts with standard CLI checks.",
        "",
        "## Open Questions",
        "",
        "- None currently.",
        ""
    ].join("\n");
    assertPlanningAuthoringCompliance("slice_overview", text);
    return text;
}
function assertPlanningAuthoringCompliance(artifactType, markdownText) {
    const issues = (0, authoring_policy_1.auditPlanningArtifactAuthoring)({
        artifactPath: "generated slice 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));
    }
}
