"use strict";
/**
 * API profile lifecycle service.
 *
 * Discovery, registration, copy, export, and import for API profiles.
 */
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 (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.importApiProfileBundle = exports.exportApiProfile = exports.copyApiProfile = exports.registerApiProfileOrphans = exports.discoverApiProfileOrphans = void 0;
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const target_metadata_1 = require("../../targets/target-metadata");
const config_manager_1 = require("../../utils/config-manager");
const websearch_manager_1 = require("../../utils/websearch-manager");
const image_analysis_1 = require("../../utils/image-analysis");
const sensitive_keys_1 = require("../../utils/sensitive-keys");
const reserved_names_1 = require("../../config/reserved-names");
const validation_service_1 = require("./validation-service");
const profile_reader_1 = require("./profile-reader");
const profile_lifecycle_validation_1 = require("./profile-lifecycle-validation");
const config_loader_facade_1 = require("../../config/config-loader-facade");
const SETTINGS_FILE_SUFFIX = '.settings.json';
const REDACTED_TOKEN_SENTINEL = '__CCS_REDACTED__';
function parseTargetValue(value) {
    if ((0, target_metadata_1.isPersistedTargetType)(value)) {
        return value;
    }
    return null;
}
function validateProfileNameForPath(name, label) {
    const validationError = (0, validation_service_1.validateApiName)(name);
    if (validationError) {
        return `Invalid ${label} profile name "${name}": ${validationError}`;
    }
    return null;
}
function getProfileSettingsPath(name) {
    return path.join((0, config_loader_facade_1.getCcsDir)(), `${name}${SETTINGS_FILE_SUFFIX}`);
}
function writeJsonObjectAtomically(filePath, value) {
    const dir = path.dirname(filePath);
    if (!fs.existsSync(dir)) {
        fs.mkdirSync(dir, { recursive: true });
    }
    const tempPath = `${filePath}.tmp`;
    fs.writeFileSync(tempPath, JSON.stringify(value, null, 2) + '\n', 'utf8');
    fs.renameSync(tempPath, filePath);
}
function registerApiProfileInConfig(name, target, force = false) {
    if ((0, config_loader_facade_1.isUnifiedMode)()) {
        (0, config_loader_facade_1.mutateConfig)((config) => {
            if (config.profiles[name] && !force) {
                throw new Error(`API profile already exists: ${name}`);
            }
            config.profiles[name] = {
                type: 'api',
                settings: `~/.ccs/${name}${SETTINGS_FILE_SUFFIX}`,
                ...(target !== 'claude' && { target }),
            };
        });
        return;
    }
    const configPath = (0, config_manager_1.getConfigPath)();
    const config = (0, config_loader_facade_1.loadConfigSafe)();
    if (config.profiles[name] && !force) {
        throw new Error(`API profile already exists: ${name}`);
    }
    config.profiles[name] = `~/.ccs/${name}${SETTINGS_FILE_SUFFIX}`;
    config.profile_targets = config.profile_targets || {};
    if (target === 'claude') {
        delete config.profile_targets[name];
    }
    else {
        config.profile_targets[name] = target;
    }
    writeJsonObjectAtomically(configPath, config);
}
function getRegisteredSettingsFileNames() {
    const { profiles, variants } = (0, profile_reader_1.listApiProfiles)();
    const names = new Set();
    for (const profile of profiles) {
        names.add(`${profile.name}${SETTINGS_FILE_SUFFIX}`);
    }
    for (const variant of variants) {
        if (!variant.settings || variant.settings === '-')
            continue;
        names.add(path.basename(variant.settings.replace(/^~\/\.ccs\//, '')));
    }
    return names;
}
function getProfileTarget(name) {
    const { profiles } = (0, profile_reader_1.listApiProfiles)();
    return profiles.find((profile) => profile.name === name)?.target || 'claude';
}
function readJsonObject(filePath) {
    const raw = fs.readFileSync(filePath, 'utf8');
    const parsed = JSON.parse(raw);
    if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
        throw new Error('Settings file must contain a JSON object.');
    }
    return parsed;
}
function rollbackSettingsFile(filePath, previousContent, existedBefore) {
    if (existedBefore && previousContent !== null) {
        fs.writeFileSync(filePath, previousContent, 'utf8');
        return;
    }
    if (fs.existsSync(filePath)) {
        fs.unlinkSync(filePath);
    }
}
function discoverApiProfileOrphans() {
    const ccsDir = (0, config_loader_facade_1.getCcsDir)();
    if (!fs.existsSync(ccsDir)) {
        return { orphans: [] };
    }
    const registeredSettings = getRegisteredSettingsFileNames();
    const files = fs.readdirSync(ccsDir).filter((file) => file.endsWith(SETTINGS_FILE_SUFFIX));
    const ignoredNames = new Set(['cursor.settings.json']);
    const orphans = files
        .filter((file) => !registeredSettings.has(file))
        .filter((file) => !file.startsWith('base-'))
        .filter((file) => !ignoredNames.has(file))
        .filter((file) => !(0, reserved_names_1.isReservedName)(file.slice(0, -SETTINGS_FILE_SUFFIX.length)))
        .map((file) => {
        const name = file.slice(0, -SETTINGS_FILE_SUFFIX.length);
        const settingsPath = path.join(ccsDir, file);
        try {
            const settings = readJsonObject(settingsPath);
            return {
                name,
                settingsPath,
                validation: (0, profile_lifecycle_validation_1.validateApiProfileSettingsPayload)(settings),
            };
        }
        catch (error) {
            return {
                name,
                settingsPath,
                validation: {
                    valid: false,
                    issues: [
                        {
                            level: 'error',
                            code: 'invalid_json',
                            message: error.message,
                            field: 'settings',
                            hint: 'Fix JSON syntax before registration.',
                        },
                    ],
                },
            };
        }
    });
    return { orphans };
}
exports.discoverApiProfileOrphans = discoverApiProfileOrphans;
function registerApiProfileOrphans(options) {
    const discovered = discoverApiProfileOrphans();
    const selected = options?.names === undefined
        ? discovered.orphans
        : discovered.orphans.filter((orphan) => options.names?.includes(orphan.name));
    const result = { registered: [], skipped: [] };
    for (const orphan of selected) {
        const nameError = (0, validation_service_1.validateApiName)(orphan.name);
        if (nameError) {
            result.skipped.push({
                name: orphan.name,
                reason: `Invalid profile name: ${nameError}`,
            });
            continue;
        }
        if (!options?.force && !orphan.validation.valid) {
            result.skipped.push({
                name: orphan.name,
                reason: 'Validation failed. Use --force to register.',
            });
            continue;
        }
        try {
            if (orphan.validation.valid) {
                (0, websearch_manager_1.ensureWebSearchMcpOrThrow)();
                (0, image_analysis_1.ensureImageAnalysisMcpOrThrow)();
            }
            registerApiProfileInConfig(orphan.name, options?.target || 'claude', options?.force || false);
            result.registered.push(orphan.name);
        }
        catch (error) {
            result.skipped.push({ name: orphan.name, reason: error.message });
        }
    }
    return result;
}
exports.registerApiProfileOrphans = registerApiProfileOrphans;
function copyApiProfile(source, destination, options) {
    const sourceError = validateProfileNameForPath(source, 'source');
    if (sourceError)
        return { success: false, error: sourceError };
    const destinationError = (0, validation_service_1.validateApiName)(destination);
    if (destinationError)
        return { success: false, error: destinationError };
    const sourceSettingsPath = getProfileSettingsPath(source);
    if (!fs.existsSync(sourceSettingsPath)) {
        return { success: false, error: `Source profile settings not found: ${source}` };
    }
    const destinationSettingsPath = getProfileSettingsPath(destination);
    if (fs.existsSync(destinationSettingsPath) && !options?.force) {
        return { success: false, error: `Destination settings already exist: ${destination}` };
    }
    try {
        const sourceSettings = readJsonObject(sourceSettingsPath);
        const validation = (0, profile_lifecycle_validation_1.validateApiProfileSettingsPayload)(sourceSettings);
        if (!validation.valid && !options?.force) {
            return {
                success: false,
                error: 'Source profile has validation errors. Use --force to copy.',
            };
        }
        const destinationExisted = fs.existsSync(destinationSettingsPath);
        const previousDestinationContent = destinationExisted
            ? fs.readFileSync(destinationSettingsPath, 'utf8')
            : null;
        writeJsonObjectAtomically(destinationSettingsPath, sourceSettings);
        try {
            (0, websearch_manager_1.ensureWebSearchMcpOrThrow)();
            (0, image_analysis_1.ensureImageAnalysisMcpOrThrow)();
        }
        catch (hookError) {
            rollbackSettingsFile(destinationSettingsPath, previousDestinationContent, destinationExisted);
            throw hookError;
        }
        try {
            registerApiProfileInConfig(destination, options?.target || getProfileTarget(source), options?.force);
        }
        catch (registrationError) {
            rollbackSettingsFile(destinationSettingsPath, previousDestinationContent, destinationExisted);
            throw registrationError;
        }
        return {
            success: true,
            name: destination,
            settingsPath: destinationSettingsPath,
            warnings: validation.issues
                .filter((issue) => issue.level === 'warning')
                .map((issue) => issue.message),
        };
    }
    catch (error) {
        return { success: false, error: error.message };
    }
}
exports.copyApiProfile = copyApiProfile;
function exportApiProfile(name, includeSecrets = false) {
    const nameError = validateProfileNameForPath(name, 'profile');
    if (nameError)
        return { success: false, error: nameError };
    const settingsPath = getProfileSettingsPath(name);
    if (!fs.existsSync(settingsPath)) {
        return { success: false, error: `Profile settings not found: ${name}` };
    }
    try {
        const settings = readJsonObject(settingsPath);
        let redacted = false;
        if (!includeSecrets) {
            const env = settings.env;
            if (typeof env === 'object' && env !== null) {
                for (const [key, value] of Object.entries(env)) {
                    if (!(0, sensitive_keys_1.isSensitiveKey)(key) || typeof value !== 'string')
                        continue;
                    env[key] = REDACTED_TOKEN_SENTINEL;
                    redacted = true;
                }
            }
        }
        const bundle = {
            schemaVersion: 1,
            exportedAt: new Date().toISOString(),
            profile: {
                name,
                target: getProfileTarget(name),
            },
            settings,
        };
        return { success: true, bundle, redacted };
    }
    catch (error) {
        return { success: false, error: error.message };
    }
}
exports.exportApiProfile = exportApiProfile;
function importApiProfileBundle(bundle, options) {
    if (typeof bundle !== 'object' || bundle === null || Array.isArray(bundle)) {
        return { success: false, error: 'Import bundle must be a JSON object.' };
    }
    const input = bundle;
    if (input.schemaVersion !== 1 || !input.profile || !input.settings) {
        return {
            success: false,
            error: 'Invalid bundle schema. Expected schemaVersion=1 with profile and settings.',
        };
    }
    const name = options?.name || input.profile.name;
    const nameError = (0, validation_service_1.validateApiName)(name);
    if (nameError)
        return { success: false, error: nameError };
    const bundleTarget = parseTargetValue(input.profile.target);
    if (input.profile.target !== undefined && bundleTarget === null) {
        return {
            success: false,
            error: `Invalid bundle profile target. Expected: ${(0, target_metadata_1.getPersistedTargetChoices)()}.`,
        };
    }
    const settings = JSON.parse(JSON.stringify(input.settings));
    const env = settings.env;
    const warnings = [];
    if (env) {
        const redactedKeys = Object.entries(env)
            .filter(([key, value]) => (0, sensitive_keys_1.isSensitiveKey)(key) && value === REDACTED_TOKEN_SENTINEL)
            .map(([key]) => key);
        if (redactedKeys.length > 0) {
            for (const key of redactedKeys) {
                env[key] = '';
            }
            warnings.push(`Imported bundle had redacted values for ${redactedKeys.join(', ')}. Set secrets before use.`);
        }
    }
    const validation = (0, profile_lifecycle_validation_1.validateApiProfileSettingsPayload)(settings);
    if (!validation.valid && !options?.force) {
        return { success: false, error: 'Import validation failed.', validation };
    }
    const settingsPath = getProfileSettingsPath(name);
    try {
        const settingsExisted = fs.existsSync(settingsPath);
        const previousSettingsContent = settingsExisted ? fs.readFileSync(settingsPath, 'utf8') : null;
        writeJsonObjectAtomically(settingsPath, settings);
        try {
            (0, websearch_manager_1.ensureWebSearchMcpOrThrow)();
            (0, image_analysis_1.ensureImageAnalysisMcpOrThrow)();
        }
        catch (hookError) {
            rollbackSettingsFile(settingsPath, previousSettingsContent, settingsExisted);
            throw hookError;
        }
        try {
            registerApiProfileInConfig(name, options?.target || bundleTarget || 'claude', options?.force);
        }
        catch (registrationError) {
            rollbackSettingsFile(settingsPath, previousSettingsContent, settingsExisted);
            throw registrationError;
        }
        warnings.push(...validation.issues
            .filter((issue) => issue.level === 'warning')
            .map((issue) => issue.message));
        return { success: true, name, warnings, validation };
    }
    catch (error) {
        return { success: false, error: error.message, validation };
    }
}
exports.importApiProfileBundle = importApiProfileBundle;
//# sourceMappingURL=profile-lifecycle-service.js.map