import { TufVerificationError, } from "./opencode/tufTypes.js";
const TUF_REASON_CODES = [
    "expired_metadata",
    "invalid_metadata_type",
    "missing_role",
    "missing_trusted_root_key",
    "revoked_key",
    "signature_threshold_not_met",
    "signature_invalid",
    "snapshot_version_mismatch",
    "timestamp_version_mismatch",
    "rollback_attempt",
    "revoked_artifact",
    "revoked_version",
    "unknown_target",
];
const LOCAL_REASON_CODES = [
    "not_configured",
    "non_loopback_host",
    "metadata_unavailable",
    "metadata_malformed",
    "artifact_missing",
    "artifact_unreadable",
    "artifact_not_file",
    "artifact_not_executable",
    "artifact_path_invalid",
    "filesystem_error",
    "unsupported_platform",
    "verification_rejected",
    "runtime_unavailable",
    "runtime_failed",
    "readiness_timeout",
    "readiness_failed",
    "smoke_result_unreadable",
    "unknown_failure",
];
const RUNTIME_LIFECYCLE_REASON_CODES = new Set([
    ...TUF_REASON_CODES,
    ...LOCAL_REASON_CODES,
]);
const RUNTIME_LIFECYCLE_PHASES = new Set([
    "configuration",
    "metadata",
    "target_resolution",
    "artifact",
    "filesystem",
    "process",
    "readiness",
    "smoke",
    "unknown",
]);
const SAFE_REASON_MESSAGES = {
    expired_metadata: "OpenCode binary metadata is expired.",
    invalid_metadata_type: "OpenCode binary metadata has an invalid type.",
    missing_role: "OpenCode binary metadata is missing a required signing role.",
    missing_trusted_root_key: "OpenCode binary metadata does not contain a trusted root signing key.",
    revoked_key: "OpenCode binary metadata was signed by a revoked key.",
    signature_threshold_not_met: "OpenCode binary metadata does not meet the required signature threshold.",
    signature_invalid: "OpenCode binary metadata contains an invalid signature.",
    snapshot_version_mismatch: "OpenCode binary metadata versions do not match the trusted snapshot.",
    timestamp_version_mismatch: "OpenCode binary metadata versions do not match the trusted timestamp.",
    rollback_attempt: "OpenCode binary metadata is older than the minimum trusted version.",
    revoked_artifact: "OpenCode binary artifact verification failed.",
    revoked_version: "OpenCode binary version has been revoked.",
    unknown_target: "OpenCode binary target is not present in trusted metadata.",
    not_configured: "OpenCode binary verification metadata is not configured.",
    non_loopback_host: "OpenCode runtime host must be loopback.",
    metadata_unavailable: "OpenCode binary metadata is unavailable.",
    metadata_malformed: "OpenCode binary metadata could not be parsed.",
    artifact_missing: "OpenCode binary artifact is unavailable.",
    artifact_unreadable: "OpenCode binary artifact could not be read.",
    artifact_not_file: "OpenCode binary artifact is not a regular file.",
    artifact_not_executable: "OpenCode binary artifact is not executable.",
    artifact_path_invalid: "OpenCode binary artifact path is not trusted.",
    filesystem_error: "OpenCode binary filesystem inspection failed.",
    unsupported_platform: "OpenCode runtime platform is unsupported.",
    verification_rejected: "OpenCode binary verification was rejected.",
    runtime_unavailable: "OpenCode runtime is unavailable.",
    runtime_failed: "OpenCode runtime failed.",
    readiness_timeout: "OpenCode runtime readiness timed out.",
    readiness_failed: "OpenCode runtime readiness failed.",
    smoke_result_unreadable: "OpenCode runtime smoke result could not be read.",
    unknown_failure: "OpenCode runtime lifecycle inspection failed.",
};
const TUF_PHASES = {
    expired_metadata: "metadata",
    invalid_metadata_type: "metadata",
    missing_role: "metadata",
    missing_trusted_root_key: "metadata",
    revoked_key: "metadata",
    signature_threshold_not_met: "metadata",
    signature_invalid: "metadata",
    snapshot_version_mismatch: "metadata",
    timestamp_version_mismatch: "metadata",
    rollback_attempt: "metadata",
    revoked_artifact: "artifact",
    revoked_version: "target_resolution",
    unknown_target: "target_resolution",
};
const LOCAL_PHASES = {
    not_configured: "configuration",
    non_loopback_host: "configuration",
    metadata_unavailable: "metadata",
    metadata_malformed: "metadata",
    artifact_missing: "artifact",
    artifact_unreadable: "artifact",
    artifact_not_file: "artifact",
    artifact_not_executable: "artifact",
    artifact_path_invalid: "artifact",
    filesystem_error: "filesystem",
    unsupported_platform: "target_resolution",
    verification_rejected: "unknown",
    runtime_unavailable: "process",
    runtime_failed: "process",
    readiness_timeout: "readiness",
    readiness_failed: "readiness",
    smoke_result_unreadable: "smoke",
    unknown_failure: "unknown",
};
export class RuntimeLifecycleError extends Error {
    reasonCode;
    phase;
    constructor(reasonCode, phase = phaseForReasonCode(reasonCode), options = {}) {
        super(safeReasonForCode(reasonCode), options.cause === undefined ? undefined : { cause: options.cause });
        this.reasonCode = reasonCode;
        this.phase = phase;
        this.name = "RuntimeLifecycleError";
    }
}
export function createRuntimeLifecycleDiagnostic(input) {
    const phase = input.phase ?? phaseForReasonCode(input.reasonCode);
    return {
        reasonCode: input.reasonCode,
        phase,
        reason: safeReasonForCode(input.reasonCode),
        timestamp: normalizeTimestamp(input.timestamp),
    };
}
export function sanitizeRuntimeLifecycleDiagnostic(input, fallback) {
    const reasonCode = isRuntimeLifecycleReasonCode(input?.reasonCode)
        ? input.reasonCode
        : fallback.reasonCode;
    const timestamp = typeof input?.timestamp === "string" ? input.timestamp : undefined;
    return createRuntimeLifecycleDiagnostic({
        reasonCode,
        phase: isRuntimeLifecyclePhase(input?.phase)
            ? input.phase
            : (fallback.phase ?? phaseForReasonCode(reasonCode)),
        ...(timestamp ? { timestamp } : {}),
    });
}
export function diagnosticFromLifecycleError(error, fallback = { reasonCode: "unknown_failure" }) {
    if (error instanceof RuntimeLifecycleError) {
        return createRuntimeLifecycleDiagnostic({
            reasonCode: error.reasonCode,
            phase: error.phase,
        });
    }
    if (error instanceof TufVerificationError) {
        return createRuntimeLifecycleDiagnostic({
            reasonCode: error.code,
            phase: phaseForReasonCode(error.code),
        });
    }
    return sanitizeRuntimeLifecycleDiagnostic(undefined, fallback);
}
export function sanitizeOpenCodeBinaryStatus(status) {
    const safe = {
        state: status.state,
    };
    if (isSafeLifecycleLabel(status.opencodeVersion)) {
        safe.opencodeVersion = status.opencodeVersion;
    }
    if (isSafeLifecycleLabel(status.platform))
        safe.platform = status.platform;
    if (isSafeTargetPath(status.targetPath))
        safe.targetPath = status.targetPath;
    if (isSafeTimestamp(status.verifiedAt)) {
        safe.verifiedAt = new Date(status.verifiedAt).toISOString();
    }
    if (status.state !== "verified" || status.reasonCode || status.reason) {
        const diagnostic = sanitizeRuntimeLifecycleDiagnostic(status, {
            reasonCode: fallbackReasonCodeForBinaryState(status.state),
        });
        safe.reason = diagnostic.reason;
        safe.reasonCode = diagnostic.reasonCode;
        safe.phase = diagnostic.phase;
        safe.timestamp = diagnostic.timestamp;
    }
    else if (isSafeTimestamp(status.timestamp)) {
        safe.timestamp = new Date(status.timestamp).toISOString();
    }
    return safe;
}
export function classifyRuntimeFailureDiagnostic(input) {
    if (isRuntimeLifecycleReasonCode(input?.reasonCode)) {
        return sanitizeRuntimeLifecycleDiagnostic(input, {
            reasonCode: input.reasonCode,
        });
    }
    const reason = typeof input?.reason === "string" ? input.reason : "";
    const timestamp = typeof input?.timestamp === "string" ? input.timestamp : undefined;
    if (/timed?\s*out|timeout/i.test(reason)) {
        return createRuntimeLifecycleDiagnostic({
            reasonCode: "readiness_timeout",
            phase: "readiness",
            ...(timestamp ? { timestamp } : {}),
        });
    }
    if (/readiness|health\s*check|ECONNREFUSED|fetch failed/i.test(reason)) {
        return createRuntimeLifecycleDiagnostic({
            reasonCode: "readiness_failed",
            phase: "readiness",
            ...(timestamp ? { timestamp } : {}),
        });
    }
    return sanitizeRuntimeLifecycleDiagnostic(input, {
        reasonCode: "runtime_failed",
        phase: "process",
    });
}
export function phaseForReasonCode(reasonCode) {
    if (isTufReasonCode(reasonCode))
        return TUF_PHASES[reasonCode];
    return LOCAL_PHASES[reasonCode];
}
export function safeReasonForCode(reasonCode) {
    return SAFE_REASON_MESSAGES[reasonCode];
}
export function isRuntimeLifecycleReasonCode(value) {
    return (typeof value === "string" &&
        RUNTIME_LIFECYCLE_REASON_CODES.has(value));
}
export function isRuntimeLifecyclePhase(value) {
    return (typeof value === "string" &&
        RUNTIME_LIFECYCLE_PHASES.has(value));
}
function fallbackReasonCodeForBinaryState(state) {
    if (state === "not_configured")
        return "not_configured";
    if (state === "metadata_unavailable")
        return "metadata_unavailable";
    if (state === "unverified")
        return "verification_rejected";
    if (state === "rejected")
        return "verification_rejected";
    return "unknown_failure";
}
function normalizeTimestamp(value) {
    if (value instanceof Date && Number.isFinite(value.getTime())) {
        return value.toISOString();
    }
    if (typeof value === "string" && isSafeTimestamp(value)) {
        return new Date(value).toISOString();
    }
    return new Date().toISOString();
}
function isSafeTimestamp(value) {
    if (typeof value !== "string" || value.length > 64)
        return false;
    const parsed = new Date(value);
    return Number.isFinite(parsed.getTime());
}
function isSafeLifecycleLabel(value) {
    return (typeof value === "string" &&
        value.length > 0 &&
        value.length <= 80 &&
        /^[A-Za-z0-9._+:-]+$/.test(value) &&
        !looksLikeHash(value) &&
        !looksLikeLocalPath(value));
}
function isSafeTargetPath(value) {
    return (typeof value === "string" &&
        value.length > 0 &&
        value.length <= 120 &&
        /^[A-Za-z0-9._/-]+$/.test(value) &&
        !value.startsWith("/") &&
        !value.includes("..") &&
        !value.includes("\\") &&
        !/^[A-Za-z]:/.test(value) &&
        !looksLikeHash(value));
}
function looksLikeHash(value) {
    return /\b[a-f0-9]{32,}\b/i.test(value);
}
function looksLikeLocalPath(value) {
    return (value.startsWith("/") ||
        value.startsWith("~/") ||
        /^[A-Za-z]:[\\/]/.test(value) ||
        value.includes("/Users/") ||
        value.includes("/tmp/") ||
        value.includes("/var/folders/"));
}
function isTufReasonCode(value) {
    return TUF_REASON_CODES.includes(value);
}
