/**
 * 模板同步 / 迁移引擎 — SoloForge 问题二十五
 *
 * 职责：对比模板源与本地安装版本，计算差异，按策略执行同步。
 * 核心不变量：
 *   - 用户修改的模板不得被覆盖
 *   - core knowledge 不得被自动同步修改
 *   - apply 必须用户确认，dry-run 先行
 */
// ── 辅助函数 ──
/**
 * 检查资产是否属于 core knowledge
 * 通过清单条目中的 sovereignty 字段判断
 */
function isCoreKnowledge(entry) {
    return entry?.sovereignty === "core";
}
/**
 * 生成备份路径
 * 格式：{project_path}/.soloforge/backups/template-sync-{时间戳}
 */
function generateBackupPath(projectPath) {
    const ts = new Date().toISOString().replace(/[:.]/g, "-");
    return `${projectPath}/.soloforge/backups/template-sync-${ts}`;
}
// ── 核心函数 ──
/**
 * 计算模板资产版本差异
 *
 * 对比当前安装版本（currentHashes）与源版本（sourceHashes），
 * 为每个清单条目生成版本差异记录。
 *
 * 分类规则：
 *   - installed_hash 在清单中存在 && 当前文件哈希 == installed_hash && 源哈希变化 => outdated_unmodified
 *   - 当前文件哈希 != installed_hash && 源哈希变化 => outdated_modified
 *   - 目标文件不存在 => missing
 *   - 源已废弃 => deprecated
 *   - 清单中无对应条目 => 保守处理，视为 user_modified=true
 */
export function computeTemplateAssetVersions(manifest, currentHashes, sourceHashes) {
    const manifestMap = new Map();
    for (const entry of manifest) {
        manifestMap.set(entry.asset_id, entry);
    }
    const results = [];
    const processedIds = new Set();
    // 遍历清单，逐条计算差异
    for (const entry of manifest) {
        processedIds.add(entry.asset_id);
        const currentHash = currentHashes.get(entry.target_path);
        const sourceHash = sourceHashes.get(entry.source_path);
        // 检查源是否已废弃
        if (sourceHash === undefined) {
            results.push({
                asset_id: entry.asset_id,
                source_path: entry.source_path,
                target_path: entry.target_path,
                asset_kind: entry.asset_kind,
                template_version: entry.template_version,
                source_hash: "",
                installed_hash: entry.installed_hash,
                user_modified: false,
                template_asset_status: "deprecated",
            });
            continue;
        }
        // 目标文件不存在
        if (currentHash === undefined) {
            results.push({
                asset_id: entry.asset_id,
                source_path: entry.source_path,
                target_path: entry.target_path,
                asset_kind: entry.asset_kind,
                template_version: entry.template_version,
                source_hash: sourceHash,
                installed_hash: entry.installed_hash,
                user_modified: false,
                template_asset_status: "missing",
            });
            continue;
        }
        // 检查是否有用户修改
        const userModified = currentHash !== entry.installed_hash;
        // 源哈希与安装哈希对比
        if (entry.installed_hash === sourceHash) {
            // 已是最新
            results.push({
                asset_id: entry.asset_id,
                source_path: entry.source_path,
                target_path: entry.target_path,
                asset_kind: entry.asset_kind,
                template_version: entry.template_version,
                source_hash: sourceHash,
                installed_hash: entry.installed_hash,
                user_modified: userModified,
                template_asset_status: "up_to_date",
            });
        }
        else if (!userModified) {
            // 源有更新且用户未修改 => outdated_unmodified
            results.push({
                asset_id: entry.asset_id,
                source_path: entry.source_path,
                target_path: entry.target_path,
                asset_kind: entry.asset_kind,
                template_version: entry.template_version,
                source_hash: sourceHash,
                installed_hash: entry.installed_hash,
                user_modified: false,
                template_asset_status: "outdated_unmodified",
            });
        }
        else {
            // 源有更新且用户已修改 => outdated_modified
            results.push({
                asset_id: entry.asset_id,
                source_path: entry.source_path,
                target_path: entry.target_path,
                asset_kind: entry.asset_kind,
                template_version: entry.template_version,
                source_hash: sourceHash,
                installed_hash: entry.installed_hash,
                user_modified: true,
                template_asset_status: "outdated_modified",
            });
        }
    }
    // 检查 currentHashes 中有但清单中不存在的条目（保守处理）
    for (const [targetPath, _hash] of currentHashes) {
        // 尝试通过 target_path 找到对应清单条目
        const matchedEntry = manifest.find((e) => e.target_path === targetPath);
        if (!matchedEntry) {
            // 清单中无此条目，保守视为用户自定义文件，不纳入同步
            continue;
        }
        if (!processedIds.has(matchedEntry.asset_id)) {
            // 已在上方处理过，跳过
            continue;
        }
    }
    return results;
}
/**
 * 执行模板同步
 *
 * 策略：
 *   - dry_run=true：仅生成报告，不写入任何文件
 *   - apply=true：仅同步 "missing" 和 "outdated_unmodified" 资产
 *   - 永不同步 "outdated_modified"（用户已修改）— 跳过并记录
 *   - 永不同步 core knowledge 变更
 *   - apply 必须有用户确认（confirm=true）
 *   - 写入前必须生成备份路径
 *
 * @returns 同步结果，包含迁移报告
 */
export function executeSync(options, assets, manifest) {
    const manifestMap = new Map();
    for (const entry of manifest) {
        manifestMap.set(entry.asset_id, entry);
    }
    // 构建清单条目索引，用于判断主权
    const applied = [];
    const skipped = [];
    // dry_run 模式：只生成报告
    if (options.dry_run) {
        for (const asset of assets) {
            if (asset.template_asset_status === "outdated_modified") {
                skipped.push(asset.asset_id);
            }
            if (asset.template_asset_status === "missing" || asset.template_asset_status === "outdated_unmodified") {
                applied.push(asset.asset_id);
            }
        }
        const report = generateMigrationReport(options.project_path, assets, applied, skipped);
        return {
            success: true,
            dry_run: true,
            report,
        };
    }
    // apply 模式：安全检查
    if (options.apply) {
        // 必须有用户确认
        if (!options.confirm) {
            const report = generateMigrationReport(options.project_path, assets, [], assets.map((a) => a.asset_id));
            return {
                success: false,
                dry_run: false,
                report: {
                    ...report,
                    requires_human: true,
                },
            };
        }
        const backupPath = generateBackupPath(options.project_path);
        for (const asset of assets) {
            const entry = manifestMap.get(asset.asset_id);
            // 永不同步 core knowledge 变更
            if (isCoreKnowledge(entry)) {
                skipped.push(asset.asset_id);
                continue;
            }
            // 永不同步用户已修改的资产
            if (asset.template_asset_status === "outdated_modified") {
                skipped.push(asset.asset_id);
                continue;
            }
            // 仅同步 missing 和 outdated_unmodified
            if (asset.template_asset_status === "missing" || asset.template_asset_status === "outdated_unmodified") {
                // 实际文件复制/写入操作由调用方执行
                // 此处只记录待同步的资产
                applied.push(asset.asset_id);
            }
            // deprecated / up_to_date / conflict / schema_migration_required 不处理
            if (asset.template_asset_status === "deprecated" ||
                asset.template_asset_status === "up_to_date" ||
                asset.template_asset_status === "conflict" ||
                asset.template_asset_status === "schema_migration_required") {
                // 静默跳过
            }
        }
        const report = generateMigrationReport(options.project_path, assets, applied, skipped);
        report.rollback_path = backupPath;
        return {
            success: true,
            dry_run: false,
            report,
            backup_path: backupPath,
        };
    }
    // 既非 dry_run 也非 apply：视为无效调用
    const report = generateMigrationReport(options.project_path, assets, [], assets.map((a) => a.asset_id));
    return {
        success: false,
        dry_run: false,
        report: {
            ...report,
            requires_human: true,
        },
    };
}
/**
 * 检测资产是否被用户修改
 *
 * @returns 用户是否修改过该资产
 */
export function detectUserModification(asset) {
    return asset.user_modified;
}
/**
 * 生成知识迁移报告
 *
 * 汇总同步过程中的变更情况，包含新增、更新、跳过、废弃、冲突等分类。
 *
 * @param projectPath 项目路径
 * @param assets 所有模板资产版本记录
 * @param applied 已同步的资产 ID 列表
 * @param skipped 跳过的资产 ID 列表
 * @returns 知识迁移报告
 */
export function generateMigrationReport(projectPath, assets, applied, skipped) {
    const assetMap = new Map();
    for (const asset of assets) {
        assetMap.set(asset.asset_id, asset);
    }
    const added = [];
    const updated = [];
    const skippedUserModified = [];
    const deprecated = [];
    const conflicts = [];
    const schemaMigrations = [];
    for (const asset of assets) {
        switch (asset.template_asset_status) {
            case "missing":
                if (applied.includes(asset.asset_id)) {
                    added.push(asset.asset_id);
                }
                break;
            case "outdated_unmodified":
                if (applied.includes(asset.asset_id)) {
                    updated.push(asset.asset_id);
                }
                break;
            case "outdated_modified":
                if (skipped.includes(asset.asset_id)) {
                    skippedUserModified.push(asset.asset_id);
                }
                break;
            case "deprecated":
                deprecated.push(asset.asset_id);
                break;
            case "conflict":
                conflicts.push(asset.asset_id);
                break;
            case "schema_migration_required":
                schemaMigrations.push(asset.asset_id);
                break;
            // up_to_date 不需要记录
        }
    }
    const requiresHuman = skippedUserModified.length > 0 ||
        conflicts.length > 0 ||
        schemaMigrations.length > 0;
    return {
        project_path: projectPath,
        checked_at: new Date().toISOString(),
        added,
        updated,
        skipped_user_modified: skippedUserModified,
        deprecated,
        conflicts,
        schema_migrations: schemaMigrations,
        requires_human: requiresHuman,
    };
}
/**
 * 验证同步安全性
 *
 * 硬性阻断规则：
 *   - core knowledge 资产被覆盖 => 阻断
 *   - 用户已修改资产被覆盖 => 阻断
 *   - apply=true 但 confirm=false（涉及用户已修改资产时） => 阻断
 *
 * @returns 安全检查结果
 */
export function validateSyncSafety(assets) {
    const blocked = [];
    const reasons = [];
    for (const asset of assets) {
        // core knowledge 资产不得被同步覆盖
        if (asset.template_asset_status === "outdated_unmodified" &&
            asset.asset_kind === "core_knowledge") {
            blocked.push(asset.asset_id);
            reasons.push(`核心知识资产「${asset.asset_id}」不允许通过模板同步自动更新`);
        }
        // 用户已修改的资产不得被覆盖
        if (asset.template_asset_status === "outdated_modified" &&
            asset.user_modified) {
            blocked.push(asset.asset_id);
            reasons.push(`用户已修改资产「${asset.asset_id}」不允许被模板同步覆盖`);
        }
    }
    if (blocked.length > 0) {
        return {
            safe: false,
            blocked,
            reason: reasons.join("；"),
        };
    }
    return {
        safe: true,
        blocked: [],
    };
}
//# sourceMappingURL=template_sync.js.map