import fs from "node:fs";
import path from "node:path";
import { CAE_WORKSPACE_ARTIFACT_ROOT, classifyCaeRegistryIdNamespace } from "./workspace-artifact-conventions.js";
function parseMetadata(raw) {
    if (!raw.trim())
        return {};
    try {
        const parsed = JSON.parse(raw);
        if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
            return {};
        return parsed;
    }
    catch {
        return {};
    }
}
function trimString(value) {
    if (typeof value !== "string")
        return null;
    const normalized = value.trim();
    return normalized.length > 0 ? normalized : null;
}
function inferOverrideOfId(metadata, overlay) {
    const explicit = trimString(overlay?.overrideOfId);
    if (explicit)
        return explicit;
    const candidates = [
        metadata.overrideOfId,
        metadata.sourceDefaultArtifactId,
        metadata.sourceArtifactId,
        metadata.clonedFromArtifactId,
        metadata.copiedFromArtifactId,
        metadata.baseArtifactId
    ];
    for (const candidate of candidates) {
        const normalized = trimString(candidate);
        if (normalized)
            return normalized;
    }
    return null;
}
function inferLifecycleStatus(retiredAt, overlay) {
    if (overlay?.hidden === true)
        return "hidden";
    if (typeof retiredAt === "string" && retiredAt.trim().length > 0)
        return "retired";
    return "active";
}
function isWorkspaceArtifactPath(refPath) {
    return refPath === CAE_WORKSPACE_ARTIFACT_ROOT || refPath.startsWith(`${CAE_WORKSPACE_ARTIFACT_ROOT}/`);
}
function resolveArtifactFileState(workspaceRoot, refPath, source) {
    const absolutePath = path.resolve(workspaceRoot, refPath);
    const fileExists = fs.existsSync(absolutePath);
    if (!fileExists) {
        return { fileExists: false, fileOwnershipStatus: "missing-file" };
    }
    if (isWorkspaceArtifactPath(refPath)) {
        return { fileExists: true, fileOwnershipStatus: "workspace-owned" };
    }
    if (source === "default") {
        return { fileExists: true, fileOwnershipStatus: "default-owned" };
    }
    return { fileExists: true, fileOwnershipStatus: "external-allowed" };
}
function deriveArtifactSource(artifactId, overrideOfId) {
    if (overrideOfId)
        return "override";
    const namespace = classifyCaeRegistryIdNamespace(artifactId);
    if (namespace === "workspace")
        return "workspace";
    return "default";
}
function deriveArtifactStatus(lifecycleStatus, fileOwnershipStatus, fileExists) {
    if (lifecycleStatus === "hidden")
        return "hidden";
    if (lifecycleStatus === "retired")
        return "retired";
    if (!fileExists)
        return "missing-file";
    if (fileOwnershipStatus === "external-allowed")
        return "external-allowed";
    return "active";
}
function parseArtifactRefs(raw) {
    try {
        const parsed = JSON.parse(raw);
        if (!Array.isArray(parsed))
            return [];
        const refs = [];
        for (const item of parsed) {
            if (!item || typeof item !== "object" || Array.isArray(item))
                continue;
            const artifactId = trimString(item.artifactId);
            if (artifactId)
                refs.push({ artifactId });
        }
        return refs;
    }
    catch {
        return [];
    }
}
function parseJsonRecord(raw) {
    if (!raw || !raw.trim())
        return null;
    try {
        const parsed = JSON.parse(raw);
        return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
    }
    catch {
        return null;
    }
}
function summarizeScope(raw) {
    const scope = parseJsonRecord(raw);
    const conditions = Array.isArray(scope?.conditions) ? scope.conditions : [];
    if (conditions.length === 0)
        return "Always";
    return conditions
        .map((condition) => {
        if (!condition || typeof condition !== "object" || Array.isArray(condition))
            return "unknown condition";
        const row = condition;
        const kind = String(row.kind ?? "condition");
        if (kind === "always")
            return "Always";
        if (kind === "phaseKey")
            return `Phase ${String(row.value ?? "")}`.trim();
        if (kind === "commandName")
            return `Command ${String(row.match ?? "is")} ${String(row.value ?? "")}`.trim();
        if (kind === "commandArgEquals")
            return `Arg ${String(row.path ?? "")} equals ${String(row.value ?? "")}`.trim();
        if (kind === "taskIdPattern")
            return `Task ID ${String(row.pattern ?? "")}`.trim();
        if (kind === "taskTag") {
            const values = Array.isArray(row.values) ? row.values.map((value) => String(value)).join(", ") : String(row.value ?? "");
            return `Task tag ${String(row.match ?? "has")} ${values}`.trim();
        }
        return `${kind} ${String(row.value ?? "")}`.trim();
    })
        .filter(Boolean)
        .join("; ");
}
function summarizeAcknowledgement(raw) {
    const ack = parseJsonRecord(raw);
    const strength = trimString(ack?.strength);
    if (!strength || strength === "none")
        return null;
    return { strength, token: trimString(ack?.token) };
}
function deriveActivationSource(activationId, overrideOfId) {
    if (overrideOfId)
        return "override";
    const namespace = classifyCaeRegistryIdNamespace(activationId);
    if (namespace === "workspace")
        return "workspace";
    return "default";
}
function deriveActivationStatus(lifecycleStatus, lifecycleState) {
    if (lifecycleStatus === "hidden")
        return "hidden";
    if (lifecycleStatus === "retired")
        return "retired";
    const normalized = lifecycleState.trim().toLowerCase();
    if (normalized === "draft")
        return "draft";
    if (normalized === "disabled")
        return "disabled";
    return "active";
}
export function classifyCaeAuthoringArtifactRow(input) {
    const metadata = parseMetadata(input.row.metadata_json || "{}");
    const overrideOfId = inferOverrideOfId(metadata, input.overlay);
    const source = deriveArtifactSource(input.row.artifact_id, overrideOfId);
    const lifecycleStatus = inferLifecycleStatus(input.row.retired_at, input.overlay);
    const fileState = resolveArtifactFileState(input.workspaceRoot, input.row.path, source);
    return {
        schemaVersion: 1,
        activeVersionId: input.activeVersionId,
        registryDigest: input.registryDigest,
        artifactId: input.row.artifact_id,
        artifactType: input.row.artifact_type,
        title: input.row.title,
        path: input.row.path,
        source,
        lifecycleStatus,
        status: deriveArtifactStatus(lifecycleStatus, fileState.fileOwnershipStatus, fileState.fileExists),
        fileOwnershipStatus: fileState.fileOwnershipStatus,
        fileExists: fileState.fileExists,
        overrideOfId
    };
}
export function classifyCaeAuthoringActivationRow(input) {
    const metadata = parseMetadata(input.row.metadata_json || "{}");
    const overrideOfId = inferOverrideOfId(metadata, input.overlay);
    const source = deriveActivationSource(input.row.activation_id, overrideOfId);
    const lifecycleStatus = inferLifecycleStatus(input.row.retired_at, input.overlay);
    const artifactRefs = parseArtifactRefs(input.row.artifact_refs_json).map((ref) => {
        const artifact = input.artifactsById?.get(ref.artifactId) ?? null;
        return {
            artifactId: ref.artifactId,
            source: artifact?.source ?? null,
            status: artifact?.status ?? "missing-artifact-row",
            fileOwnershipStatus: artifact?.fileOwnershipStatus ?? null
        };
    });
    const statusWarnings = artifactRefs.flatMap((ref) => {
        if (ref.status === "missing-artifact-row")
            return [`Missing artifact ${ref.artifactId}`];
        if (ref.status !== "active")
            return [`Artifact ${ref.artifactId} is ${ref.status}`];
        return [];
    });
    const scopeSummary = summarizeScope(input.row.scope_json);
    if (scopeSummary === "Always" && input.row.family === "policy") {
        statusWarnings.push("Policy applies broadly");
    }
    return {
        schemaVersion: 1,
        activeVersionId: input.activeVersionId,
        registryDigest: input.registryDigest,
        activationId: input.row.activation_id,
        family: input.row.family,
        priority: input.row.priority,
        scopeJson: input.row.scope_json,
        scopeSummary,
        lifecycleState: input.row.lifecycle_state,
        source,
        lifecycleStatus,
        status: deriveActivationStatus(lifecycleStatus, input.row.lifecycle_state),
        overrideOfId,
        acknowledgement: summarizeAcknowledgement(input.row.acknowledgement_json),
        artifactRefs,
        statusWarnings
    };
}
export function buildCaeAuthoringClassificationSnapshot(input) {
    const artifacts = [...input.artifactRows]
        .sort((left, right) => left.artifact_id.localeCompare(right.artifact_id))
        .map((row) => classifyCaeAuthoringArtifactRow({
        workspaceRoot: input.workspaceRoot,
        activeVersionId: input.activeVersionId,
        registryDigest: input.registryDigest,
        row,
        overlay: input.artifactOverlayById?.[row.artifact_id]
    }));
    const artifactMap = new Map(artifacts.map((artifact) => [artifact.artifactId, artifact]));
    const activations = [...input.activationRows]
        .sort((left, right) => left.activation_id.localeCompare(right.activation_id))
        .map((row) => classifyCaeAuthoringActivationRow({
        activeVersionId: input.activeVersionId,
        registryDigest: input.registryDigest,
        row,
        overlay: input.activationOverlayById?.[row.activation_id],
        artifactsById: artifactMap
    }));
    return {
        schemaVersion: 1,
        activeVersionId: input.activeVersionId,
        registryDigest: input.registryDigest,
        artifacts,
        activations
    };
}
