"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.resolveConfigSetWritePolicy = resolveConfigSetWritePolicy;
exports.planConfigWrite = planConfigWrite;
const node_path_1 = __importDefault(require("node:path"));
const toml = __importStar(require("@iarna/toml"));
const config_catalog_1 = require("./config-catalog");
const config_layer_files_1 = require("./config-layer-files");
const preservation_1 = require("./preservation");
const errors_1 = require("../errors");
const paths_1 = require("../paths");
const runtime_contract_1 = require("../runtime/runtime-contract");
function resolveConfigSetWritePolicy(key) {
    const catalogEntry = config_catalog_1.CONFIG_CATALOG_BY_KEY[key];
    if (catalogEntry === undefined) {
        if ((0, config_catalog_1.isSensitiveUnsupportedConfigKeyPath)(key)) {
            throw createConfigSetBoundaryError({
                key,
                findingCode: "SENSITIVE_UNSUPPORTED_CONFIG_KEY",
                detail: `Unknown sensitive config key '${key}' resembles license/reminder state, generated reminder artifacts, managed reminder regions, or commercial policy constants and is not writable through day-shift config set.`
            });
        }
        throw createConfigSetBoundaryError({
            key,
            findingCode: "UNKNOWN_CONFIG_KEY",
            detail: `Unknown config key '${key}' is not a catalog-backed config set target.`
        });
    }
    const writePolicy = catalogEntry.writePolicy;
    if (writePolicy.supported === true &&
        (writePolicy.surface === "config-set-shared" ||
            writePolicy.surface === "config-set-local")) {
        return {
            catalogEntry,
            writePolicy
        };
    }
    throw createConfigSetBoundaryError({
        key,
        findingCode: isSensitiveCatalogEntry(catalogEntry)
            ? "SENSITIVE_UNSUPPORTED_CONFIG_KEY"
            : "UNSUPPORTED_CONFIG_SURFACE",
        detail: createConfigSetRejectionDetail(key, catalogEntry)
    });
}
function planConfigWrite(options) {
    const targetLayer = getWritableConfigTargetLayer(options.writePolicy);
    const targetRelativePath = getWritableConfigRelativePath(options.writePolicy);
    const canonicalTarget = (0, paths_1.assertCanonicalWriteTarget)(targetRelativePath, targetRelativePath);
    const configPath = (0, paths_1.resolveRuntimeAbsolutePath)(options.repositoryContext.root, canonicalTarget).absolutePath;
    const acceptedValue = parseAcceptedValue({
        catalogEntry: options.catalogEntry,
        rawValue: options.rawValue
    });
    const structuralPressureThresholdKey = parseStructuralPressureThresholdKey(options.writePolicy.persistedConfigKey);
    const structuralPressureExclusionKey = parseStructuralPressureExclusionKey(options.writePolicy.persistedConfigKey);
    if (structuralPressureThresholdKey !== null) {
        validateStructuralPressureThresholdWrite({
            key: options.catalogEntry.key,
            existingContents: options.existingContents,
            thresholdKey: structuralPressureThresholdKey,
            acceptedValue
        });
    }
    const rewrite = preservation_1.preservation.toml.rewrite({
        currentContent: options.existingContents,
        values: createPersistedTomlPatch(options.writePolicy.persistedConfigKey, acceptedValue)
    });
    return {
        key: options.catalogEntry.key,
        targetLayer,
        targetRelativePath,
        filePath: configPath,
        contents: rewrite.contents,
        acceptedValue,
        displayValue: formatDisplaySafeAcceptedValue(options.catalogEntry, acceptedValue),
        preservationStrategy: structuralPressureThresholdKey === null && structuralPressureExclusionKey === null
            ? "toml-top-level-key"
            : "toml-nested-key",
        catalogEntry: options.catalogEntry
    };
}
function getWritableConfigTargetLayer(writePolicy) {
    return writePolicy.surface === "config-set-local" ? "local" : "repository";
}
function getWritableConfigRelativePath(writePolicy) {
    return node_path_1.default.posix.join(runtime_contract_1.DAY_SHIFT_DIRECTORY_NAME, writePolicy.surface === "config-set-local" ? runtime_contract_1.LOCAL_CONFIG_FILE_NAME : runtime_contract_1.CONFIG_FILE_NAME);
}
function parseAcceptedValue(options) {
    switch (options.catalogEntry.valueType) {
        case "string":
        case "enum":
        case "path":
        case "directory-path":
        case "file-path":
            return validateParsedValue({
                catalogEntry: options.catalogEntry,
                value: options.rawValue
            });
        case "integer":
        case "count":
            return validateParsedValue({
                catalogEntry: options.catalogEntry,
                value: parseIntegerValue(options.catalogEntry, options.rawValue)
            });
        case "number":
            return validateParsedValue({
                catalogEntry: options.catalogEntry,
                value: parseNumberValue(options.catalogEntry, options.rawValue)
            });
        case "boolean":
            return validateParsedValue({
                catalogEntry: options.catalogEntry,
                value: parseBooleanValue(options.catalogEntry, options.rawValue)
            });
        case "array":
            return validateParsedValue({
                catalogEntry: options.catalogEntry,
                value: parseArrayValue(options.catalogEntry, options.rawValue)
            });
        default:
            throw createConfigSetValueError({
                key: options.catalogEntry.key,
                detail: `Config key '${options.catalogEntry.key}' uses unsupported value type '${options.catalogEntry.valueType}' for day-shift config set.`
            });
    }
}
function validateParsedValue(options) {
    const ruleKind = options.catalogEntry.validationRule.kind;
    if (ruleKind === "string" && typeof options.value !== "string") {
        throw createConfigSetValueError({
            key: options.catalogEntry.key,
            detail: `Invalid value for config key '${options.catalogEntry.key}'; expected a string.`
        });
    }
    if (ruleKind === "positive-integer-ordered-threshold" &&
        (!Number.isInteger(options.value) || Number(options.value) <= 0)) {
        throw createConfigSetValueError({
            key: options.catalogEntry.key,
            detail: `Invalid value for config key '${options.catalogEntry.key}'; expected a positive integer.`
        });
    }
    return options.value;
}
function parseIntegerValue(catalogEntry, rawValue) {
    if (catalogEntry.validationRule.kind === "positive-integer-ordered-threshold") {
        if (!/^\d+$/.test(rawValue)) {
            throw createConfigSetValueError({
                key: catalogEntry.key,
                detail: `Invalid value for config key '${catalogEntry.key}'; expected a positive integer.`
            });
        }
        const parsedPositiveInteger = Number(rawValue);
        if (!Number.isInteger(parsedPositiveInteger) || parsedPositiveInteger <= 0) {
            throw createConfigSetValueError({
                key: catalogEntry.key,
                detail: `Invalid value for config key '${catalogEntry.key}'; expected a positive integer.`
            });
        }
        return parsedPositiveInteger;
    }
    if (!/^-?\d+$/.test(rawValue)) {
        throw createConfigSetValueError({
            key: catalogEntry.key,
            detail: `Invalid value for config key '${catalogEntry.key}'; expected an integer.`
        });
    }
    return Number(rawValue);
}
function parseNumberValue(catalogEntry, rawValue) {
    const parsed = Number(rawValue);
    if (!Number.isFinite(parsed)) {
        throw createConfigSetValueError({
            key: catalogEntry.key,
            detail: `Invalid value for config key '${catalogEntry.key}'; expected a number.`
        });
    }
    return parsed;
}
function parseBooleanValue(catalogEntry, rawValue) {
    if (rawValue === "true") {
        return true;
    }
    if (rawValue === "false") {
        return false;
    }
    throw createConfigSetValueError({
        key: catalogEntry.key,
        detail: `Invalid value for config key '${catalogEntry.key}'; expected true or false.`
    });
}
function parseArrayValue(catalogEntry, rawValue) {
    let parsed;
    try {
        parsed = JSON.parse(rawValue);
    }
    catch {
        throw createConfigSetValueError({
            key: catalogEntry.key,
            detail: `Invalid value for config key '${catalogEntry.key}'; expected a JSON array of non-empty strings.`
        });
    }
    const expectedTypeDescription = (0, config_layer_files_1.validateStructuralPressureScanExclusionArrayValue)({
        keyPath: catalogEntry.key,
        value: parsed
    });
    if (expectedTypeDescription !== null) {
        throw createConfigSetValueError({
            key: catalogEntry.key,
            detail: `Invalid value for config key '${catalogEntry.key}'; expected ${normalizeArrayExpectedTypeDescription(expectedTypeDescription)}.`
        });
    }
    return parsed;
}
function normalizeArrayExpectedTypeDescription(expectedTypeDescription) {
    if (expectedTypeDescription.startsWith("an array of ")) {
        return `a JSON array of ${expectedTypeDescription.slice("an array of ".length)}`;
    }
    return expectedTypeDescription;
}
function formatDisplaySafeAcceptedValue(catalogEntry, acceptedValue) {
    if (catalogEntry.sensitivity === "sensitive" ||
        catalogEntry.sensitivity === "secret" ||
        catalogEntry.inventoryDisplay.mode !== "printable") {
        return "<redacted>";
    }
    if (Array.isArray(acceptedValue)) {
        return JSON.stringify(acceptedValue);
    }
    return typeof acceptedValue === "string" ? acceptedValue : String(acceptedValue);
}
function createPersistedTomlPatch(persistedConfigKey, acceptedValue) {
    const structuralPressureThresholdKey = parseStructuralPressureThresholdKey(persistedConfigKey);
    const structuralPressureExclusionKey = parseStructuralPressureExclusionKey(persistedConfigKey);
    if (structuralPressureThresholdKey !== null) {
        return {
            structural_pressure: {
                [structuralPressureThresholdKey.family]: {
                    [structuralPressureThresholdKey.threshold]: acceptedValue
                }
            }
        };
    }
    if (structuralPressureExclusionKey !== null) {
        return {
            structural_pressure: {
                [structuralPressureExclusionKey]: acceptedValue
            }
        };
    }
    return {
        [persistedConfigKey]: acceptedValue
    };
}
function parseStructuralPressureExclusionKey(key) {
    const match = /^structural_pressure\.(excluded_extensions|blocked_segments|excluded_basenames)$/.exec(key);
    if (match === null) {
        return null;
    }
    return match[1];
}
function validateStructuralPressureThresholdWrite(options) {
    if (!Number.isInteger(options.acceptedValue) || Number(options.acceptedValue) <= 0) {
        throw createConfigSetValueError({
            key: options.key,
            detail: `Invalid value for config key '${options.key}'; expected a positive integer.`
        });
    }
    const acceptedThresholdValue = Number(options.acceptedValue);
    const currentDocument = parseExistingTomlDocument(options.existingContents);
    const structuralPressure = isPlainObject(currentDocument.structural_pressure)
        ? currentDocument.structural_pressure
        : {};
    const configuredFamilyCandidate = structuralPressure[options.thresholdKey.family];
    const configuredFamily = isPlainObject(configuredFamilyCandidate)
        ? configuredFamilyCandidate
        : {};
    const configuredThresholds = {};
    for (const threshold of ["watch", "pressure", "hotspot"]) {
        const configuredValue = configuredFamily[threshold];
        if (typeof configuredValue === "number") {
            configuredThresholds[threshold] = configuredValue;
        }
    }
    const thresholds = {
        ...config_layer_files_1.STRUCTURAL_PRESSURE_THRESHOLD_DEFAULTS[options.thresholdKey.family],
        ...configuredThresholds,
        [options.thresholdKey.threshold]: acceptedThresholdValue
    };
    if (thresholds.watch <= thresholds.pressure && thresholds.pressure <= thresholds.hotspot) {
        return;
    }
    throw createConfigSetThresholdOrderingError({
        key: options.key,
        family: options.thresholdKey.family
    });
}
function parseExistingTomlDocument(currentContent) {
    if (currentContent.trim() === "") {
        return {};
    }
    const parsedDocument = toml.parse(currentContent);
    if (!isPlainObject(parsedDocument)) {
        return {};
    }
    return parsedDocument;
}
function parseStructuralPressureThresholdKey(key) {
    const match = /^structural_pressure\.(source|test)\.(watch|pressure|hotspot)$/.exec(key);
    if (match === null) {
        return null;
    }
    return {
        family: match[1],
        threshold: match[2]
    };
}
function isPlainObject(value) {
    return typeof value === "object" && value !== null && !Array.isArray(value);
}
function createConfigSetRejectionDetail(key, catalogEntry) {
    const writePolicy = catalogEntry.writePolicy;
    if (writePolicy.supported === false) {
        return `Config key '${key}' is catalog-visible but is not writable through day-shift config set. ${writePolicy.rejectionReason}`;
    }
    return `Config key '${key}' is owned by the ${catalogEntry.owningCommandFamily} command family and is not writable through day-shift config set.`;
}
function createConfigSetBoundaryError(options) {
    const finding = {
        code: options.findingCode,
        message: options.detail,
        severity: "error",
        path: options.key
    };
    return (0, errors_1.createInvalidConfigError)(`Invalid config set target '${options.key}'.`, [options.detail], [finding]);
}
function createConfigSetValueError(options) {
    const finding = {
        code: "INVALID_CONFIG_VALUE_TYPE",
        message: options.detail,
        severity: "error",
        path: options.key
    };
    return (0, errors_1.createInvalidConfigError)(`Invalid config set value for '${options.key}'.`, [options.detail], [finding]);
}
function createConfigSetThresholdOrderingError(options) {
    const detail = `Invalid structural-pressure threshold ordering in [structural_pressure.${options.family}]: expected watch <= pressure <= hotspot.`;
    const finding = {
        code: "INVALID_CONFIG_THRESHOLD_ORDERING",
        message: detail,
        severity: "error",
        path: options.key
    };
    return (0, errors_1.createInvalidConfigError)(`Invalid config set value for '${options.key}'.`, [detail], [finding]);
}
function isSensitiveCatalogEntry(catalogEntry) {
    return catalogEntry.sensitivity === "sensitive" ||
        catalogEntry.sensitivity === "secret" ||
        catalogEntry.key.startsWith("license.") ||
        catalogEntry.key.startsWith("reminder.");
}
