"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.EVIDENCE_PROFILES = exports.AGENT_MODES = void 0;
exports.projectArtifactPolicy = projectArtifactPolicy;
exports.isAgentMode = isAgentMode;
exports.isEvidenceProfile = isEvidenceProfile;
const paths_1 = require("../paths");
const planning_document_utils_1 = require("./planning-document-utils");
const task_lifecycle_1 = require("./task-lifecycle");
const workflow_topology_1 = require("./workflow-topology");
exports.AGENT_MODES = ["autonomous", "guided", "interactive"];
exports.EVIDENCE_PROFILES = ["runtime", "contract", "hybrid"];
const ORGANIZATION_PARENT_KEYS = [
    "work_overview",
    "milestone_overview",
    "phase_overview",
    "slice_overview"
];
const PARENT_KEYS = [...ORGANIZATION_PARENT_KEYS, "task_definition"];
function projectArtifactPolicy(markdownText) {
    const document = (0, planning_document_utils_1.parseMarkdownFrontMatter)(markdownText);
    const lines = document.frontMatterLines;
    const findings = [];
    const compatibilityEvidence = [];
    if (!document.hasFrontMatter) {
        findings.push(finding("front-matter", "artifact", "Artifact is missing YAML front matter."));
    }
    for (const field of [
        "artifact_type",
        "id",
        "task",
        "workflow_level",
        "agent_mode",
        "evidence_profile",
        "execution_mode",
        "readiness",
        "status"
    ]) {
        if (readTopLevelValues(lines, field).length > 1) {
            findings.push(finding("duplicate-field", field, `Front matter field '${field}' is duplicated.`));
        }
    }
    const artifactType = scalar(lines, "artifact_type");
    if (artifactType !== "task_definition" && artifactType !== "implementation_summary") {
        findings.push(finding("unsupported-artifact-type", "artifact_type", `Shared task policy projection does not support '${artifactType ?? "(missing)"}'.`));
    }
    const explicitId = scalar(lines, "id");
    const taskSlug = scalar(lines, "task");
    if (explicitId !== null && taskSlug !== null && explicitId !== taskSlug) {
        findings.push(finding("conflicting-task-identity", "id", `Task identity '${explicitId}' conflicts with task slug '${taskSlug}'.`));
    }
    const taskId = explicitId ?? taskSlug;
    if (taskId === null) {
        findings.push(finding("missing-task-identity", "task", "Task identity is missing."));
    }
    else if (explicitId === null) {
        compatibilityEvidence.push(compatibility("legacy-task-identity", "id", null, taskId));
    }
    const parents = readParents(lines, findings);
    const topologyProjection = (0, workflow_topology_1.projectWorkflowTopology)({
        workflowLevel: scalar(lines, "workflow_level"),
        planningDepth: scalar(lines, "planning_depth"),
        organizationParents: readOrganizationParentKinds(lines)
    });
    for (const entry of topologyProjection.compatibilityEvidence) {
        pushCompatibility(compatibilityEvidence, compatibility(entry.code, entry.field, entry.sourceValue, entry.projectedValue));
    }
    for (const entry of topologyProjection.blockingFindings) {
        pushFinding(findings, finding(entry.code, entry.field, entry.message));
    }
    const agentMode = resolveArtifactAgentMode(lines, findings, compatibilityEvidence);
    const evidenceProfile = resolveArtifactEvidenceProfile(lines, findings, compatibilityEvidence);
    const lifecycle = projectLifecycle(markdownText, artifactType, lines, findings, compatibilityEvidence);
    if (scalar(lines, "next_action") !== null) {
        findings.push(finding("derived-state-persisted", "next_action", "Derived next_action must not be persisted as canonical artifact state."));
    }
    return {
        artifactType,
        taskId,
        taskIdentitySource: explicitId !== null ? "id" : taskSlug !== null ? "task" : null,
        topology: topologyProjection.topology,
        workflowLevel: topologyProjection.workflowLevel,
        workflowLevelSource: topologyProjection.workflowLevelSource,
        declaredAgentMode: agentMode.declared,
        effectiveAgentMode: agentMode.effective,
        agentModeSource: agentMode.source,
        evidenceProfile: evidenceProfile.profile,
        evidenceProfileSource: evidenceProfile.source,
        lifecycle,
        parents,
        compatibilityEvidence,
        blockingFindings: findings
    };
}
function resolveArtifactAgentMode(lines, findings, compatibilityEvidence) {
    const value = scalar(lines, "agent_mode");
    if (value === null) {
        compatibilityEvidence.push(compatibility("missing-agent-mode", "agent_mode", null, "guided"));
        return { declared: null, effective: "guided", source: "built-in" };
    }
    if (!isAgentMode(value)) {
        findings.push(finding("unsupported-agent-mode", "agent_mode", `Agent mode '${value}' is unsupported.`));
        return { declared: null, effective: "guided", source: "built-in" };
    }
    return { declared: value, effective: value, source: "artifact" };
}
function resolveArtifactEvidenceProfile(lines, findings, compatibilityEvidence) {
    const canonical = scalar(lines, "evidence_profile");
    const legacy = scalar(lines, "execution_mode");
    if (canonical !== null && !isEvidenceProfile(canonical)) {
        findings.push(finding("unsupported-evidence-profile", "evidence_profile", `Evidence profile '${canonical}' is unsupported.`));
    }
    if (legacy !== null && !isEvidenceProfile(legacy)) {
        findings.push(finding("unsupported-legacy-execution-mode", "execution_mode", `Legacy execution mode '${legacy}' is unsupported.`));
    }
    if (canonical !== null && legacy !== null && canonical !== legacy) {
        findings.push(finding("conflicting-evidence-profile", "evidence_profile", `Evidence profile '${canonical}' conflicts with legacy execution mode '${legacy}'.`));
    }
    if (canonical !== null && isEvidenceProfile(canonical)) {
        if (legacy !== null) {
            compatibilityEvidence.push(compatibility("redundant-legacy-execution-mode", "execution_mode", legacy, canonical));
        }
        return { profile: canonical, source: "artifact" };
    }
    if (legacy !== null && isEvidenceProfile(legacy)) {
        compatibilityEvidence.push(compatibility("legacy-execution-mode", "execution_mode", legacy, legacy));
        return { profile: legacy, source: "legacy-execution-mode" };
    }
    if (canonical === null && legacy === null) {
        findings.push(finding("missing-evidence-profile", "evidence_profile", "Evidence profile is missing and no legacy execution_mode alias is available."));
    }
    return { profile: null, source: null };
}
function projectLifecycle(markdownText, artifactType, lines, findings, compatibilityEvidence) {
    const rawReadiness = scalar(lines, "readiness");
    const readiness = normalizeLifecycleToken(rawReadiness);
    if (rawReadiness !== null && readiness !== rawReadiness) {
        compatibilityEvidence.push(compatibility("legacy-readiness-token", "readiness", rawReadiness, readiness));
    }
    const status = normalizeLifecycleToken(scalar(lines, "status"));
    let implementationStatus = normalizeLifecycleToken(scalar(lines, "implementation_status"));
    const readinessReviewId = scalar(lines, "readiness_review_id");
    let currentAttemptId = scalar(lines, "current_attempt_id");
    let reviewDisposition = normalizeLifecycleToken(scalar(lines, "review_disposition"));
    if (artifactType === "task_definition") {
        validateTaskLifecycleToken(status, "status", task_lifecycle_1.TASK_STATUSES, ["active", "blocked"], findings, compatibilityEvidence);
        validateTaskLifecycleToken(readiness, "readiness", task_lifecycle_1.TASK_READINESS_VALUES, ["completed"], findings, compatibilityEvidence);
        for (const [field, value] of [
            ["implementation_status", implementationStatus],
            ["review_disposition", reviewDisposition]
        ]) {
            if (value !== null) {
                findings.push(finding("wrong-owner-lifecycle-field", field, `Lifecycle field '${field}' belongs to implementation-summary current-attempt evidence.`));
            }
        }
    }
    if (artifactType === "implementation_summary") {
        const canonical = (0, task_lifecycle_1.projectImplementationSummaryLifecycle)(markdownText);
        for (const entry of canonical.blockingFindings) {
            pushFinding(findings, finding(entry.code, entry.field, entry.message));
        }
        for (const entry of canonical.compatibilityEvidence) {
            pushCompatibility(compatibilityEvidence, compatibility(entry.code, entry.field, entry.sourceValue, entry.projectedValue));
        }
        const summary = canonical.value;
        currentAttemptId = summary.currentAttemptId;
        implementationStatus = summary.currentAttempt?.implementationStatus
            ?? summary.legacyImplementationStatus;
        reviewDisposition = summary.currentAttempt?.reviewDisposition
            ?? summary.legacyReviewDisposition;
    }
    if (readiness === "ready_to_implement" && readinessReviewId === null) {
        compatibilityEvidence.push(compatibility("unmaterialized-readiness-review", "readiness_review_id", null, null));
    }
    return {
        readiness,
        rawReadiness,
        status,
        implementationStatus,
        readinessReviewId,
        currentAttemptId,
        reviewDisposition
    };
}
function validateTaskLifecycleToken(value, field, canonical, legacy, findings, compatibilityEvidence) {
    if (value === null)
        return;
    if (canonical.includes(value))
        return;
    if (legacy.includes(value)) {
        compatibilityEvidence.push(compatibility(`legacy-${field}-value`, field, value, field === "status" ? "draft" : "ready_to_implement"));
        return;
    }
    findings.push(finding("unsupported-lifecycle-token", field, `Unsupported task ${field} '${value}'.`));
}
function readParents(lines, findings) {
    const parents = [];
    for (const key of PARENT_KEYS) {
        const values = readUpstreamValues(lines, key);
        if (values.length > 1) {
            findings.push(finding("duplicate-parent-relationship", `upstream.${key}`, `Parent relationship '${key}' is duplicated.`));
        }
        for (const value of values) {
            try {
                const parsed = (0, paths_1.parseRepositoryRelativePath)(value);
                parents.push({ kind: key, path: parsed.normalizedPath });
            }
            catch (error) {
                findings.push(finding("unsafe-parent-relationship", `upstream.${key}`, error instanceof Error ? error.message : String(error)));
            }
        }
    }
    return parents;
}
function readOrganizationParentKinds(lines) {
    return ORGANIZATION_PARENT_KEYS.flatMap((key) => readUpstreamValues(lines, key).map(() => key));
}
function scalar(lines, key) {
    const value = (0, planning_document_utils_1.readTopLevelField)(lines, key)?.trim();
    return value === undefined || value === "" || value === "null" || value === "~" ? null : value;
}
function readTopLevelValues(lines, key) {
    const values = [];
    for (const line of lines) {
        if (/^\s/.test(line))
            continue;
        const match = line.match(/^([A-Za-z0-9_]+):\s*(.*)$/);
        if (match?.[1] === key)
            values.push((0, planning_document_utils_1.parseScalar)(match[2]));
    }
    return values;
}
function readUpstreamValues(lines, key) {
    const values = [];
    let inUpstream = false;
    for (const line of lines) {
        if (/^upstream:\s*$/.test(line)) {
            inUpstream = true;
            continue;
        }
        if (!inUpstream)
            continue;
        if (/^[^\s]/.test(line))
            break;
        const match = line.match(/^\s{2}([A-Za-z0-9_]+):\s*(.*)$/);
        if (match?.[1] === key)
            values.push((0, planning_document_utils_1.parseScalar)(match[2]));
    }
    return values.filter((value) => value.trim() !== "");
}
function normalizeLifecycleToken(value) {
    return value === null
        ? null
        : value.trim().toLowerCase().replace(/[\s-]+/g, "_");
}
function isAgentMode(value) {
    return exports.AGENT_MODES.includes(value);
}
function isEvidenceProfile(value) {
    return exports.EVIDENCE_PROFILES.includes(value);
}
function finding(code, field, message) {
    return { code, field, message };
}
function compatibility(code, field, sourceValue, projectedValue) {
    return { code, field, sourceValue, projectedValue };
}
function pushFinding(findings, entry) {
    if (!findings.some((candidate) => candidate.code === entry.code
        && candidate.field === entry.field
        && candidate.message === entry.message)) {
        findings.push(entry);
    }
}
function pushCompatibility(compatibilityEvidence, entry) {
    if (!compatibilityEvidence.some((candidate) => candidate.code === entry.code
        && candidate.field === entry.field
        && candidate.sourceValue === entry.sourceValue
        && candidate.projectedValue === entry.projectedValue)) {
        compatibilityEvidence.push(entry);
    }
}
