/**
 * Configuration Precedence Contract — Resolution
 *
 * 配置字段解析、上位约束执行、过期检测、字段分类、证据来源映射。
 */
import { PRECEDENCE_ORDER, EVIDENCE_SOURCE_MAP, SOURCE_LIFETIME, C_CLASS_FIELDS, } from "./constants.js";
import { debug } from "../../core/logger.js";
import { createConfigValueEvidence } from "./evidence.js";
// ── 查询函数 ──
/** 列出所有配置优先级规则 — 导入自 constants，通过 index 重导出 */
/** 获取配置来源的优先级排名（数值越小优先级越高）
 * @param source - 配置来源
 * @returns 优先级排名索引
 */
export function getPrecedenceRank(source) {
    return PRECEDENCE_ORDER.indexOf(source);
}
/** 获取配置来源的生命周期
 * @param source - 配置来源
 * @returns 生命周期类型
 */
export function getSourceLifetime(source) {
    return SOURCE_LIFETIME[source];
}
/** 判断来源 a 的优先级是否高于来源 b
 * @param a - 配置来源 a
 * @param b - 配置来源 b
 * @returns a 是否优先级更高
 */
export function isHigherPriority(a, b) {
    return getPrecedenceRank(a) < getPrecedenceRank(b);
}
// ── 解析 ──
/** 解析单个配置字段 — 按优先级排序候选值并检测冲突
 * @param fieldPath - 字段路径
 * @param candidates - 候选值列表
 * @returns 配置解析报告
 */
export function resolveConfigField(fieldPath, candidates) {
    const sorted = [...candidates].sort((a, b) => getPrecedenceRank(a.source) - getPrecedenceRank(b.source));
    if (sorted.length === 0) {
        return {
            field_path: fieldPath,
            selected: { source: "global_default", value: undefined, confidence: 0, field_path: fieldPath, updated_at: new Date().toISOString() },
            candidates: [],
            conflicts: [],
            lifetime: "global",
        };
    }
    const selected = sorted[0];
    const conflicts = [];
    for (let i = 1; i < sorted.length; i++) {
        const candidate = sorted[i];
        if (JSON.stringify(candidate.value) !== JSON.stringify(selected.value)) {
            conflicts.push({
                source_a: selected.source,
                source_b: candidate.source,
                field_path: fieldPath,
                reason: buildConflictReason(selected.source, candidate.source, fieldPath),
                requires_human: candidate.source === "confirmed_config" && selected.source === "fingerprint"
                    ? false
                    : isHighStakesField(fieldPath),
            });
        }
    }
    return {
        field_path: fieldPath,
        selected,
        candidates: sorted,
        conflicts,
        lifetime: SOURCE_LIFETIME[selected.source],
    };
}
/** 解析所有配置字段
 * @param fieldCandidates - 字段路径到候选值列表的映射
 * @returns 所有字段的解析报告数组
 */
export function resolveAllFields(fieldCandidates) {
    const reports = [];
    for (const [fieldPath, candidates] of Object.entries(fieldCandidates)) {
        if (candidates.length > 0) {
            reports.push(resolveConfigField(fieldPath, candidates));
        }
    }
    return reports;
}
// ── 上位约束执行 ──
/** 检查上位约束是否阻止该配置
 * @param report - 配置解析报告
 * @param guardId - 上位约束 ID
 * @returns 约束检查结果
 */
export function checkGuardOverride(report, guardId) {
    if (isGuardProtectedField(report.field_path, guardId)) {
        debug("配置优先级", "字段 %s 被上位约束 %s 阻止", report.field_path, guardId);
        return {
            blocked: true,
            report: {
                ...report,
                overridden_by_guard: guardId,
            },
        };
    }
    return { blocked: false, report };
}
function isGuardProtectedField(fieldPath, guard) {
    const GUARD_FIELDS = {
        enforced_guard: ["*"],
        privacy_secret_policy: ["delivery", "secrets", "accounts", "external_integrations"],
        command_safety: ["destructive_command_policy", "verify_timeout"],
        delivery_authorization: ["delivery.auto_push", "delivery.auto_pr", "delivery.deploy"],
        data_sovereignty: ["core_knowledge", "compliance", "privacy_policy"],
        destructive_action_gate: ["destructive_command_policy", "scope_exclusion"],
    };
    const protectedFields = GUARD_FIELDS[guard] ?? [];
    if (protectedFields.includes("*"))
        return true;
    return protectedFields.some((f) => fieldPath.startsWith(f));
}
// ── 过期检测 ──
/** 检测配置是否过期 — 比较确认值与指纹值是否一致
 * @param confirmedValue - 已确认的配置值
 * @param fingerprintValue - 当前指纹值
 * @returns 是否过期及警告信息
 */
export function detectStaleConfig(confirmedValue, fingerprintValue) {
    if (confirmedValue.source !== "confirmed_config")
        return { isStale: false, warning: "" };
    if (fingerprintValue.source !== "fingerprint")
        return { isStale: false, warning: "" };
    if (JSON.stringify(confirmedValue.value) !== JSON.stringify(fingerprintValue.value)) {
        debug("配置优先级", "字段 %s 配置过期，确认值与指纹不一致", confirmedValue.field_path);
        return {
            isStale: true,
            warning: `config_stale_warning: ${confirmedValue.field_path} 的确认值 (${JSON.stringify(confirmedValue.value)}) 与当前 fingerprint (${JSON.stringify(fingerprintValue.value)}) 不一致 — 建议重新确认`,
        };
    }
    return { isStale: false, warning: "" };
}
// ── 字段分类写入规则 ──
/** 判断字段是否为 C 类字段
 * @param fieldPath - 字段路径
 * @returns 是否为 C 类字段
 */
export function isCClassField(fieldPath) {
    return C_CLASS_FIELDS.some(f => fieldPath.startsWith(f));
}
/** 获取配置字段的分类（C 类或 B 类）
 * @param fieldPath - 字段路径
 * @param explicitClass - 显式指定的分类（可选）
 * @returns 字段分类
 */
export function getConfigFieldClass(fieldPath, explicitClass) {
    if (explicitClass)
        return explicitClass;
    if (isCClassField(fieldPath))
        return "C";
    return "B";
}
/** 判断字段是否允许自动写入
 * @param fieldPath - 字段路径
 * @param fieldClass - 字段分类
 * @param source - 配置来源
 * @returns 是否允许及原因
 */
export function canAutoWriteField(fieldPath, fieldClass, source) {
    const canonical = mapEvidenceSource(source);
    // C 类: 永不自动写入 (only confirmed_config allowed)
    if (fieldClass === "C" || isCClassField(fieldPath)) {
        if (canonical !== "confirmed_config") {
            return { allowed: false, reason: `C 类字段 ${fieldPath} 不得自动写入，必须 user_declared 或 confirmed` };
        }
    }
    // B 类: 需要高置信 (confirmed_config or fingerprint)
    if (fieldClass === "B") {
        if (canonical !== "fingerprint" && canonical !== "confirmed_config") {
            return { allowed: false, reason: `B 类字段 ${fieldPath} 需要高置信来源 (detected/user_declared/confirmed)` };
        }
    }
    // CLI flag 不静默写入 config
    if (source === "cli_flag" || source === "mcp_param") {
        return { allowed: false, reason: "CLI/MCP 参数不静默写入 config，仅对本次 invocation/task 有效" };
    }
    return { allowed: true, reason: "" };
}
// ── 证据来源映射 ──
/** 将证据元数据来源映射为规范配置来源
 * @param source - 原始来源标识
 * @returns 规范配置来源
 */
export function mapEvidenceSource(source) {
    return EVIDENCE_SOURCE_MAP[source] ?? source;
}
export function resolveConfigFromSources(fields) {
    const resolutions = [];
    const reports = [];
    const warnings = [];
    for (const [fieldPath, rawSources] of Object.entries(fields)) {
        let candidates;
        // 检测旧格式与新 FieldCandidates 格式
        if (Array.isArray(rawSources)) {
            candidates = rawSources;
        }
        else {
            // 旧格式: { config_value, fingerprint_value, user_override }
            const sources = rawSources;
            candidates = [];
            if (sources.user_override !== undefined) {
                candidates.push(createConfigValueEvidence(fieldPath, sources.user_override, "user_task", 1.0));
            }
            if (sources.config_value !== undefined) {
                candidates.push(createConfigValueEvidence(fieldPath, sources.config_value, "confirmed_config", 0.9));
            }
            if (sources.fingerprint_value !== undefined) {
                candidates.push(createConfigValueEvidence(fieldPath, sources.fingerprint_value, "fingerprint", 0.8));
            }
        }
        if (candidates.length === 0)
            continue;
        const report = resolveConfigField(fieldPath, candidates);
        reports.push(report);
        const resolution = {
            field_path: fieldPath,
            resolved_value: report.selected.value,
            source: report.selected.source,
        };
        // 检测过期: confirmed_config 与 fingerprint 不一致
        const configEv = candidates.find(c => c.source === "confirmed_config");
        const fpEv = candidates.find(c => c.source === "fingerprint");
        if (configEv && fpEv) {
            const stale = detectStaleConfig(configEv, fpEv);
            if (stale.isStale) {
                resolution.stale_warning = stale.warning;
                warnings.push(stale.warning);
            }
        }
        if (report.conflicts.length > 0) {
            resolution.conflict_report = buildConflictReport(report);
        }
        resolutions.push(resolution);
    }
    return { resolutions, reports, warnings };
}
// ── 内部辅助 ──
function buildConflictReason(higher, lower, fieldPath) {
    return `${sourceLabel(higher)} 与 ${sourceLabel(lower)} 在字段 ${fieldPath} 上存在冲突`;
}
function isHighStakesField(fieldPath) {
    const highStakes = [
        "delivery", "scope", "product_profile", "secrets", "accounts",
        "production_database", "destructive_command_policy", "compliance",
    ];
    return highStakes.some((f) => fieldPath.startsWith(f));
}
export function sourceLabel(source) {
    const labels = {
        user_task: "用户本次指令",
        cli_flag: "CLI 参数",
        mcp_param: "MCP 参数",
        confirmed_config: "已确认配置 (config.yaml)",
        project_policy: "项目策略",
        fingerprint: "文件指纹探测",
        blueprint: "项目蓝图",
        product_profile: "产品画像默认",
        knowledge_default: "知识库默认",
        global_default: "全局默认",
    };
    return labels[source];
}
export function lifetimeLabel(lifetime) {
    const labels = {
        single_invocation: "单次调用",
        task: "本次任务",
        project_persistent: "项目持久",
        global: "全局",
    };
    return labels[lifetime];
}
// ── 冲突报告构建 ──
/** 生成配置冲突的中文报告
 * @param report - 配置解析报告
 * @returns 格式化的冲突报告文本
 */
export function buildConflictReport(report) {
    const lines = [];
    lines.push(`配置冲突报告: ${report.field_path}`);
    lines.push(`当前采用: ${sourceLabel(report.selected.source)} = ${JSON.stringify(report.selected.value)}`);
    lines.push(`生命周期: ${lifetimeLabel(report.lifetime)}`);
    for (const c of report.conflicts) {
        lines.push(`冲突: ${sourceLabel(c.source_a)} vs ${sourceLabel(c.source_b)}`);
        lines.push(`  原因: ${c.reason}`);
        if (c.requires_human) {
            lines.push(`  ⚠️ 需要人工确认`);
        }
    }
    if (report.overridden_by_guard) {
        lines.push(`⚠️ 被上位约束 ${report.overridden_by_guard} 阻止`);
    }
    lines.push(`建议: ${buildResolutionAdvice(report)}`);
    return lines.join("\n");
}
function buildResolutionAdvice(report) {
    if (report.overridden_by_guard) {
        return "上位约束生效，不可通过配置修改";
    }
    if (report.selected.source === "user_task") {
        return "本次用户指令优先，仅对本次任务生效，不写入 config";
    }
    if (report.selected.source === "cli_flag" || report.selected.source === "mcp_param") {
        return "CLI/MCP 参数仅对本次调用生效，不写入 config。如需持久化请使用 config confirm";
    }
    if (report.conflicts.some((c) => c.source_b === "fingerprint")) {
        return "fingerprint 变化未自动覆盖 confirmed_config。如需更新请使用 soloforge init --interactive";
    }
    return "当前配置已正确解析";
}
//# sourceMappingURL=resolution.js.map