"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.readResolvedConfig = readResolvedConfig;
exports.resolveStructuralPressureThresholds = resolveStructuralPressureThresholds;
exports.resolveConfigGetSelection = resolveConfigGetSelection;
exports.createConfigGetText = createConfigGetText;
exports.createConfigInventory = createConfigInventory;
exports.createConfigInventoryText = createConfigInventoryText;
exports.writeConfigValue = writeConfigValue;
exports.createConfigSetText = createConfigSetText;
const node_fs_1 = __importDefault(require("node:fs"));
const errors_1 = require("../errors");
const config_contract_1 = require("./config-contract");
const config_layer_files_1 = require("./config-layer-files");
const config_write_plan_1 = require("./config-write-plan");
const license_resolution_1 = require("../license/license-resolution");
const output_1 = require("../output");
function readResolvedConfig(repositoryContext, options = {}) {
    const persistedConfigFiles = (0, config_layer_files_1.readPersistedConfigFiles)(repositoryContext);
    const licenseProvenance = options.includeLicenseProvenance === true
        ? (0, license_resolution_1.resolveLicenseInventoryProvenance)({
            repositoryContext,
            licenseFile: options.licenseFile,
            env: options.env
        })
        : undefined;
    return {
        resolved: (0, config_contract_1.resolveDayShiftConfig)({
            repositoryContext,
            repositoryConfig: persistedConfigFiles.repositoryConfig,
            localConfig: persistedConfigFiles.localConfig,
            licenseProvenance
        }),
        repositoryConfig: persistedConfigFiles.repositoryConfig,
        localConfig: persistedConfigFiles.localConfig
    };
}
function resolveStructuralPressureThresholds(resolvedConfig) {
    return {
        source: resolveStructuralPressureThresholdFamily(resolvedConfig, "source"),
        test: resolveStructuralPressureThresholdFamily(resolvedConfig, "test")
    };
}
const CONFIG_GET_EXACT_SELECTOR_KEYS = [
    "default_readiness",
    "cli_command",
    "cli_resolution",
    "cli_verified",
    "cli_verified_via",
    "editor",
    "structural_pressure.excluded_extensions",
    "structural_pressure.blocked_segments",
    "structural_pressure.excluded_basenames",
    "structural_pressure.source.watch",
    "structural_pressure.source.pressure",
    "structural_pressure.source.hotspot",
    "structural_pressure.test.watch",
    "structural_pressure.test.pressure",
    "structural_pressure.test.hotspot"
];
const CONFIG_GET_FAMILY_SELECTOR_KEYS = {
    structural_pressure: [
        "structural_pressure.excluded_extensions",
        "structural_pressure.blocked_segments",
        "structural_pressure.excluded_basenames",
        "structural_pressure.source.watch",
        "structural_pressure.source.pressure",
        "structural_pressure.source.hotspot",
        "structural_pressure.test.watch",
        "structural_pressure.test.pressure",
        "structural_pressure.test.hotspot"
    ],
    "structural_pressure.source": [
        "structural_pressure.source.watch",
        "structural_pressure.source.pressure",
        "structural_pressure.source.hotspot"
    ],
    "structural_pressure.test": [
        "structural_pressure.test.watch",
        "structural_pressure.test.pressure",
        "structural_pressure.test.hotspot"
    ]
};
const SUPPORTED_CONFIG_GET_SELECTORS = [
    ...CONFIG_GET_EXACT_SELECTOR_KEYS,
    ...Object.keys(CONFIG_GET_FAMILY_SELECTOR_KEYS)
];
function resolveConfigGetSelection(options) {
    const familyKeys = getConfigGetFamilyEntryKeys(options.selector);
    if (familyKeys !== null) {
        return createConfigGetSelection({
            resolvedConfig: options.resolvedConfig,
            selector: options.selector,
            kind: "family",
            entryKeys: familyKeys
        });
    }
    if (isSupportedConfigGetExactSelector(options.selector)) {
        return createConfigGetSelection({
            resolvedConfig: options.resolvedConfig,
            selector: options.selector,
            kind: "exact-key",
            entryKeys: [options.selector]
        });
    }
    throw createUnsupportedConfigGetSelectorError(options.resolvedConfig, options.selector);
}
function createConfigGetText(result, selection) {
    if (selection !== undefined) {
        return createSelectedConfigGetText(selection);
    }
    const lines = [];
    for (const key of config_layer_files_1.REPOSITORY_CONFIG_KEYS) {
        const value = result.resolved.values[key];
        if (value !== undefined) {
            lines.push(`${key} = ${formatScalar(value)}`);
        }
    }
    if (result.resolved.values.editor !== undefined) {
        lines.push(`editor = ${formatScalar(result.resolved.values.editor)}`);
    }
    return lines.join("\n");
}
function createConfigInventory(result) {
    const entries = Object.keys(result.resolved.resolvedEntries)
        .sort()
        .filter((key) => result.resolved.resolvedEntries[key].catalog.discoverability === "inventory-visible")
        .map((key) => createConfigInventoryRow(result.resolved.resolvedEntries[key]));
    return {
        entries,
        entryCount: entries.length
    };
}
function createConfigInventoryText(inventory) {
    const sections = groupConfigInventoryEntries(inventory.entries);
    return [
        (0, output_1.renderTerminalSection)({
            heading: "Config inventory",
            headingStyle: "title",
            fields: [
                { label: "Entries", value: inventory.entryCount }
            ],
            lines: [
                (0, output_1.renderTerminalBoundary)({ kind: "read-only" })
            ]
        }),
        ...sections
            .filter((section) => section.entries.length > 0)
            .map((section) => (0, output_1.renderTerminalCompactList)({
            heading: section.heading,
            headingStyle: "section",
            entrySpacing: "loose",
            entries: section.entries.map((entry) => ({
                label: entry.key,
                fields: [
                    { label: "Value", value: formatInventorySafeValueForText(entry.safeValue) },
                    { label: "Status", value: `${entry.valueState}; display ${entry.inventoryDisplayMode}` },
                    { label: "Source location", value: formatConfigInventorySourceForText(entry) },
                    { label: "Owner", value: `${entry.owningCommandFamily}; ${entry.valueFamily}` },
                    { label: "Writable with config set", value: entry.writableThroughConfigSet ? "yes" : "no" },
                    { label: "Write boundary", value: entry.writePolicySurface },
                    { label: "Safety", value: `${entry.sensitivity}; ${entry.mutability}` },
                    { label: "Validation", value: entry.validationRule.kind },
                    { label: "Reason", value: entry.nonWritableReason ?? entry.futureCandidateReason ?? "none" },
                    { label: "Source details", value: entry.sourceDescription }
                ]
            }))
        }))
    ].join("\n\n");
}
function writeConfigValue(options) {
    const persistedFiles = (0, config_layer_files_1.readPersistedConfigFiles)(options.repositoryContext);
    const resolvedWritePolicy = (0, config_write_plan_1.resolveConfigSetWritePolicy)(options.key);
    const configPath = resolvedWritePolicy.writePolicy.surface === "config-set-local"
        ? persistedFiles.localConfigPath
        : persistedFiles.repositoryConfigPath;
    const existingContents = node_fs_1.default.existsSync(configPath)
        ? node_fs_1.default.readFileSync(configPath, "utf8")
        : "";
    return (0, config_write_plan_1.planConfigWrite)({
        repositoryContext: options.repositoryContext,
        catalogEntry: resolvedWritePolicy.catalogEntry,
        writePolicy: resolvedWritePolicy.writePolicy,
        rawValue: options.value,
        existingContents
    });
}
function createConfigSetText(result) {
    return (0, output_1.renderTerminalSection)({
        heading: "Config set",
        headingStyle: "title",
        fields: [
            { label: "Key", value: result.key },
            { label: "Accepted value", value: result.displayValue },
            { label: "Target layer", value: result.targetLayer },
            { label: "Target path", value: result.filePath },
            { label: "Write boundary", value: result.catalogEntry.writePolicy.surface },
            { label: "Preservation", value: result.preservationStrategy }
        ],
        lines: [
            (0, output_1.renderTerminalBoundary)({
                kind: "write-applied",
                target: result.targetRelativePath,
                targetLabel: "Config file",
                stateSurface: "persisted configuration"
            })
        ]
    });
}
function formatScalar(value) {
    if (typeof value === "string") {
        return JSON.stringify(value);
    }
    return String(value);
}
function createConfigInventoryRow(entry) {
    const nonWritableReason = getNonWritableReason(entry);
    return {
        key: entry.catalogKey,
        valueFamily: entry.catalog.valueFamily,
        valueType: entry.catalog.valueType,
        description: entry.catalog.description,
        sourceKind: entry.sourceKind,
        sourceLayer: entry.sourceLayer,
        sourcePath: entry.sourcePath,
        sourceDescription: entry.sourceDescription,
        source: {
            kind: entry.sourceKind,
            layer: entry.sourceLayer,
            path: entry.sourcePath,
            description: entry.sourceDescription
        },
        valueState: entry.valueState,
        mutability: entry.catalog.mutability,
        sensitivity: entry.catalog.sensitivity,
        owningCommandFamily: entry.catalog.owningCommandFamily,
        inventoryDisplayMode: entry.inventoryDisplay.mode,
        displayPolicy: entry.inventoryDisplay,
        safeValue: createConfigInventorySafeValue(entry),
        validationRule: entry.catalog.validationRule,
        writePolicy: entry.catalog.writePolicy,
        writePolicySurface: entry.catalog.writePolicy.surface,
        writableThroughConfigSet: entry.catalog.writePolicy.supported
            && (entry.catalog.writePolicy.surface === "config-set-shared"
                || entry.catalog.writePolicy.surface === "config-set-local"),
        ...(nonWritableReason === undefined ? {} : { nonWritableReason }),
        ...(entry.catalog.writePolicy.surface === "future-candidate"
            && nonWritableReason !== undefined
            ? { futureCandidateReason: nonWritableReason }
            : {}),
        safeToPrintEffectiveValue: entry.safeToPrintEffectiveValue
    };
}
function createConfigInventorySafeValue(entry) {
    if (entry.inventoryDisplay.mode === "printable"
        && entry.safeToPrintEffectiveValue
        && "effectiveValue" in entry) {
        return {
            state: "printed",
            effectiveValue: entry.effectiveValue,
            displayValue: formatScalar(entry.effectiveValue)
        };
    }
    if (entry.inventoryDisplay.mode === "summary-only") {
        return {
            state: "summary-only",
            summary: entry.inventoryDisplay.summaryDescription,
            provenance: entry.sourceDescription
        };
    }
    if (entry.inventoryDisplay.mode === "redacted") {
        return {
            state: "redacted",
            marker: "<redacted>",
            label: entry.inventoryDisplay.redactionLabel
        };
    }
    if (entry.inventoryDisplay.mode === "omitted") {
        return {
            state: "omitted",
            reason: entry.inventoryDisplay.omissionReason
        };
    }
    return {
        state: "not-available",
        reason: "No safe effective value is available for inventory output."
    };
}
function formatInventorySafeValueForText(value) {
    if (value.state === "printed") {
        return value.displayValue;
    }
    if (value.state === "summary-only") {
        return (0, output_1.renderTerminalSafeValueMarker)({
            treatment: "summary",
            facts: value.summary
        });
    }
    if (value.state === "redacted") {
        return (0, output_1.renderTerminalSafeValueMarker)({
            treatment: "redacted",
            reasonOrFamily: value.label
        });
    }
    if (value.state === "omitted") {
        return (0, output_1.renderTerminalSafeValueMarker)({
            treatment: "omitted",
            reason: value.reason
        });
    }
    return `not-available(${value.reason})`;
}
function groupConfigInventoryEntries(entries) {
    const sections = [
        { id: "runtime-inputs", heading: "Runtime inputs", entries: [] },
        { id: "configuration-and-metadata", heading: "Configuration and metadata", entries: [] },
        { id: "derived-runtime-state", heading: "Derived runtime state", entries: [] },
        { id: "license-and-reminders", heading: "License and reminder state", entries: [] },
        { id: "structural-pressure", heading: "Structural-pressure thresholds", entries: [] },
        { id: "future-candidates", heading: "Future candidates", entries: [] },
        { id: "other", heading: "Other inventory", entries: [] }
    ];
    const sectionsById = new Map(sections.map((section) => [section.id, section]));
    for (const entry of entries) {
        sectionsById.get(resolveConfigInventoryTextSectionId(entry))?.entries.push(entry);
    }
    return sections;
}
function resolveConfigInventoryTextSectionId(entry) {
    if (entry.valueFamily === "environment-input" || entry.valueFamily === "command-input") {
        return "runtime-inputs";
    }
    if (entry.valueFamily === "future-candidate"
        || entry.mutability === "future-candidate"
        || entry.sourceKind === "future-candidate"
        || entry.writePolicySurface === "future-candidate") {
        return "future-candidates";
    }
    if (entry.key.startsWith("structural_pressure.")) {
        return "structural-pressure";
    }
    if (entry.key.startsWith("license.") || entry.key.startsWith("reminder.") || entry.owningCommandFamily === "license") {
        return "license-and-reminders";
    }
    if (entry.valueFamily === "derived-runtime-state" || entry.key.startsWith("derived.")) {
        return "derived-runtime-state";
    }
    if (entry.valueFamily === "persisted-config"
        || entry.valueFamily === "repository-owned-path"
        || entry.valueFamily === "read-only-metadata") {
        return "configuration-and-metadata";
    }
    return "other";
}
function formatConfigInventorySourceForText(entry) {
    const parts = [entry.sourceKind];
    if (entry.sourceLayer !== undefined) {
        parts.push(entry.sourceLayer);
    }
    if (entry.sourcePath !== undefined) {
        parts.push(entry.sourcePath);
    }
    return parts.join("; ");
}
function getNonWritableReason(entry) {
    if (entry.catalog.writePolicy.supported === false) {
        return entry.catalog.writePolicy.rejectionReason;
    }
    if (entry.catalog.writePolicy.surface === "owned-command") {
        return `Owned by the ${entry.catalog.owningCommandFamily} command family, not day-shift config set.`;
    }
    return undefined;
}
function formatResolvedEntryValue(entry) {
    if (!entry.safeToPrintEffectiveValue || !("effectiveValue" in entry)) {
        return `<${entry.valueState}>`;
    }
    return formatScalar(entry.effectiveValue);
}
function createSelectedConfigGetText(selection) {
    return [
        (0, output_1.renderTerminalSection)({
            heading: "Config selection",
            headingStyle: "title",
            fields: [
                { label: "Selector", value: selection.selector },
                { label: "Selection kind", value: selection.kind },
                { label: "Selected entries", value: selection.entryKeys.length }
            ],
            lines: [
                (0, output_1.renderTerminalBoundary)({ kind: "read-only" })
            ]
        }),
        (0, output_1.renderTerminalCompactList)({
            heading: "Selected values",
            headingStyle: "section",
            entrySpacing: "loose",
            entries: selection.entryKeys.map((key) => {
                const entry = selection.entries[key];
                return {
                    label: key,
                    fields: [
                        { label: "Value", value: formatResolvedEntryValue(entry) },
                        { label: "Status", value: `${entry.valueState}; display ${entry.inventoryDisplay.mode}` },
                        { label: "Value family", value: `${entry.catalog.valueFamily}; ${entry.catalog.valueType}` },
                        { label: "Mutability", value: entry.catalog.mutability },
                        { label: "Owner", value: entry.catalog.owningCommandFamily },
                        { label: "Write boundary", value: entry.catalog.writePolicy.surface }
                    ],
                    lines: [
                        (0, output_1.renderTerminalProvenance)(createSelectedConfigProvenanceFields(entry))
                    ]
                };
            })
        })
    ].join("\n\n");
}
function createSelectedConfigProvenanceFields(entry) {
    return [
        { kind: "source", value: entry.sourceKind },
        ...(entry.sourceLayer === undefined ? [] : [{ kind: "sourceLayer", value: entry.sourceLayer }]),
        { kind: "configuredBy", value: entry.sourcePath ?? entry.sourceDescription }
    ];
}
function isSupportedConfigGetExactSelector(selector) {
    return CONFIG_GET_EXACT_SELECTOR_KEYS.includes(selector);
}
function getConfigGetFamilyEntryKeys(selector) {
    if (selector in CONFIG_GET_FAMILY_SELECTOR_KEYS) {
        return CONFIG_GET_FAMILY_SELECTOR_KEYS[selector];
    }
    return null;
}
function createConfigGetSelection(options) {
    const entries = {};
    for (const key of options.entryKeys) {
        const entry = options.resolvedConfig.resolvedEntries[key];
        if (entry === undefined) {
            throw new Error(`Resolved config is missing supported config get selector '${key}'.`);
        }
        entries[key] = entry;
    }
    return {
        selector: options.selector,
        kind: options.kind,
        entryKeys: options.entryKeys,
        entries: Object.freeze(entries)
    };
}
function createUnsupportedConfigGetSelectorError(resolvedConfig, selector) {
    const catalogEntry = resolvedConfig.resolvedEntries[selector];
    const supportedSelectors = SUPPORTED_CONFIG_GET_SELECTORS.join(", ");
    if (catalogEntry !== undefined) {
        return (0, errors_1.createInvalidConfigError)(`Unsupported config get selector '${selector}'.`, [
            `Catalog-visible value '${selector}' is not supported by day-shift config get.`,
            `Value family: ${catalogEntry.catalog.valueFamily}.`,
            `Owning command family: ${catalogEntry.catalog.owningCommandFamily}.`,
            `Supported selectors: ${supportedSelectors}.`
        ]);
    }
    return (0, errors_1.createInvalidConfigError)(`Unknown config get selector '${selector}'.`, [
        `Unknown selector '${selector}' is not a catalog-backed config get target.`,
        `Supported selectors: ${supportedSelectors}.`
    ]);
}
function resolveStructuralPressureThresholdFamily(resolvedConfig, family) {
    return {
        watch: resolveStructuralPressureThreshold(resolvedConfig, family, "watch"),
        pressure: resolveStructuralPressureThreshold(resolvedConfig, family, "pressure"),
        hotspot: resolveStructuralPressureThreshold(resolvedConfig, family, "hotspot")
    };
}
function resolveStructuralPressureThreshold(resolvedConfig, family, threshold) {
    const catalogKey = `structural_pressure.${family}.${threshold}`;
    const entry = resolvedConfig.resolvedEntries[catalogKey];
    if (entry === undefined || typeof entry.effectiveValue !== "number") {
        throw new Error(`Resolved config is missing numeric structural-pressure threshold '${catalogKey}'.`);
    }
    return {
        catalogKey,
        value: entry.effectiveValue,
        sourceKind: entry.sourceKind,
        sourceLayer: entry.sourceLayer,
        sourcePath: entry.sourcePath,
        sourceDescription: entry.sourceDescription
    };
}
