"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.installCommand = installCommand;
const fs = __importStar(require("fs-extra"));
const path = __importStar(require("path"));
const chalk_1 = __importDefault(require("chalk"));
const system_1 = require("../utils/system");
const config_1 = require("../utils/config");
const install_prompts_1 = require("../utils/install-prompts");
const update_1 = require("./update");
const EXTENSIONS_DIR = (0, config_1.getExtensionsDir)();
const PLUGIN_NAME = 'feishu-openclaw-plugin';
const PLUGIN_PATH = path.join(EXTENSIONS_DIR, PLUGIN_NAME);
const CONFLICT_PLUGIN_PATH = path.join(EXTENSIONS_DIR, 'feishu');
const PACKAGE_NAME = '@larksuiteoapi/feishu-openclaw-plugin';
function compareVersions(v1, v2) {
    const parts1 = v1.split('.').map(Number);
    const parts2 = v2.split('.').map(Number);
    for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {
        const p1 = parts1[i] || 0;
        const p2 = parts2[i] || 0;
        if (p1 > p2)
            return 1;
        if (p1 < p2)
            return -1;
    }
    return 0;
}
async function ensureChannelConfig() {
    console.log(chalk_1.default.blue('Configuring channels...'));
    let config = await (0, config_1.readConfig)();
    if (!config)
        config = {};
    // Ensure basic structure
    if (!config.channels)
        config.channels = {};
    if (!config.channels.feishu) {
        config.channels.feishu = {
            enabled: true,
            appId: "",
            appSecret: "",
            domain: "feishu",
            connectionMode: "websocket",
            requireMention: true,
            dmPolicy: "pairing",
            groupPolicy: "open",
            allowFrom: [],
            groupAllowFrom: []
        };
    }
    // Get current credentials - safely handle null/undefined
    const feishuConfig = config.channels.feishu || {};
    const currentAppId = feishuConfig.appId || "";
    // Ensure appSecret is undefined if it's null or empty string, to trigger prompt if needed?
    // Wait, if it's empty string but appId exists, we want to prompt.
    // runInstallAuthFlow handles empty string correctly (validatedSecret="").
    // But let's ensure it's not null.
    const currentAppSecret = feishuConfig.appSecret || undefined;
    // Run interactive auth flow
    const { appId, appSecret } = await (0, install_prompts_1.runInstallAuthFlow)(currentAppId, currentAppSecret);
    // Update config with validated credentials
    // Re-verify structure in case something weird happened, though unlikely
    if (!config.channels)
        config.channels = {};
    if (!config.channels.feishu)
        config.channels.feishu = feishuConfig; // Should be reference assignment
    config.channels.feishu.appId = appId;
    config.channels.feishu.appSecret = appSecret;
    // Ensure dmPolicy and groupPolicy defaults
    if (!config.channels.feishu.dmPolicy) {
        config.channels.feishu.dmPolicy = "pairing";
    }
    if (!config.channels.feishu.groupPolicy) {
        config.channels.feishu.groupPolicy = "open";
    }
    // Update plugins.allow
    if (!config.plugins)
        config.plugins = {};
    if (!config.plugins.allow)
        config.plugins.allow = [];
    if (!config.plugins.allow.includes(PLUGIN_NAME)) {
        config.plugins.allow.push(PLUGIN_NAME);
    }
    // Explicitly enable the plugin in entries as per requirement 9.2
    if (!config.plugins.entries)
        config.plugins.entries = {};
    if (!config.plugins.entries[PLUGIN_NAME]) {
        config.plugins.entries[PLUGIN_NAME] = { enabled: true };
    }
    else {
        config.plugins.entries[PLUGIN_NAME].enabled = true;
    }
    await (0, config_1.writeConfig)(config);
}
/**
 * Helper to verify installation and start OpenClaw gateway and logs.
 */
async function verifyAndStart() {
    console.log(chalk_1.default.blue('Verifying installation...'));
    const finalConfig = await (0, config_1.readConfig)();
    const checks = [
        !finalConfig.plugins?.entries?.feishu?.enabled,
        finalConfig.plugins?.entries?.[PLUGIN_NAME]?.enabled,
        await fs.pathExists(path.join(PLUGIN_PATH, 'node_modules'))
    ];
    if (checks.every(Boolean)) {
        console.log(chalk_1.default.green('Installation complete!'));
        const openclawCmd = (0, system_1.getPlatformCommand)('openclaw');
        console.log(chalk_1.default.blue('Starting OpenClaw gateway...'));
        try {
            (0, system_1.runCommand)(`${openclawCmd} gateway restart`);
        }
        catch (error) {
            console.warn(chalk_1.default.yellow('Warning: Failed to restart OpenClaw gateway.'));
        }
        // Wait a bit for gateway to initialize and produce logs
        await new Promise(resolve => setTimeout(resolve, 1000));
        console.log(chalk_1.default.blue('Tailing OpenClaw logs...'));
        try {
            await (0, system_1.spawnCommand)(openclawCmd, ['logs']);
        }
        catch (error) {
            console.warn(chalk_1.default.yellow('Warning: Failed to tail OpenClaw logs.'));
        }
    }
    else {
        console.warn(chalk_1.default.yellow('Installation finished but some checks failed. Please run "doctor" command to diagnose.'));
    }
}
async function installCommand(options) {
    console.log(chalk_1.default.blue('Starting installation...'));
    // 1. Check existing installation
    if (await fs.pathExists(PLUGIN_PATH)) {
        console.log(chalk_1.default.yellow('Plugin is already installed. Starting update process...'));
        const newVersion = await (0, update_1.updateCommand)(options, true, true);
        // Validate config after update
        try {
            await ensureChannelConfig();
        }
        catch (error) {
            console.error(chalk_1.default.red('Failed to configure channels (配置渠道失败):'));
            console.error(error);
            process.exit(1);
        }
        if (newVersion) {
            console.log(chalk_1.default.green(`Update complete! New version: ${newVersion}`));
        }
        else {
            console.log(chalk_1.default.green('Update complete!'));
        }
        // Execute verification and start logic even for updates
        await verifyAndStart();
        return;
    }
    // 2. Check openclaw version
    try {
        const openclawCmd = (0, system_1.getPlatformCommand)('openclaw');
        const output = (0, system_1.runCommandQuiet)(`${openclawCmd} --version`);
        // Parse version from output: supports "2026.2.26" and "OpenClaw 2026.3.9 (commit)"
        const versionMatch = output ? output.match(/(?:OpenClaw\s+)?(\d+\.\d+\.\d+)/) : null;
        const version = versionMatch ? versionMatch[1] : null;
        if (version && compareVersions(version, '2026.2.26') < 0) {
            console.error(chalk_1.default.red(`Error: OpenClaw version mismatch. Expected >= 2026.2.26, found ${version} (raw: ${output}). Please upgrade.`));
            process.exit(1);
        }
        else if (!version) {
            console.warn(chalk_1.default.yellow(`Warning: Could not parse OpenClaw version from "${output}". Proceeding with installation but compatibility is not guaranteed.`));
        }
    }
    catch (error) {
        console.error(chalk_1.default.red('Error: OpenClaw is not installed or not in PATH.'));
        process.exit(1);
    }
    // 3. Set npm registry
    console.log(chalk_1.default.blue('Setting npm registry...'));
    try {
        const npmCmd = (0, system_1.getPlatformCommand)('npm');
        (0, system_1.runCommand)(`${npmCmd} config set registry https://registry.npmjs.org/`);
    }
    catch (e) {
        console.error(chalk_1.default.red('Failed to set npm registry.'));
    }
    // 4. (Optional) Prompt to uninstall lark-office mcp
    console.log(chalk_1.default.yellow('Reminder: You can ask OpenClaw to "uninstall lark-office mcp" if needed.'));
    // 5. Disable built-in plugin
    console.log(chalk_1.default.blue('Disabling built-in Feishu plugin...'));
    const config = await (0, config_1.readConfig)();
    if (!config.plugins)
        config.plugins = {};
    if (!config.plugins.entries)
        config.plugins.entries = {};
    if (!config.plugins.entries.feishu)
        config.plugins.entries.feishu = { enabled: false };
    config.plugins.entries.feishu.enabled = false;
    await (0, config_1.writeConfig)(config);
    // 6. Remove conflicting directory
    if (await fs.pathExists(CONFLICT_PLUGIN_PATH)) {
        console.log(chalk_1.default.blue('Removing conflicting plugin directory...'));
        await fs.remove(CONFLICT_PLUGIN_PATH);
    }
    // 7. Install official plugin
    console.log(chalk_1.default.blue('Installing official Feishu plugin...'));
    try {
        const packageIdentifier = options.version ? `${PACKAGE_NAME}@${options.version}` : PACKAGE_NAME;
        console.log(chalk_1.default.blue(`Installing plugin ${packageIdentifier}...`));
        const openclawCmd = (0, system_1.getPlatformCommand)('openclaw');
        (0, system_1.runCommand)(`${openclawCmd} plugins install ${packageIdentifier}`);
    }
    catch (error) {
        console.error(chalk_1.default.red('Failed to install plugin from npm.'));
        console.error(error);
        process.exit(1);
    }
    // 8. Configure channels
    try {
        await ensureChannelConfig();
    }
    catch (error) {
        console.error(chalk_1.default.red('Failed to configure channels (配置渠道失败):'));
        console.error(error);
        // Optionally exit or continue? If config fails, we probably shouldn't start.
        process.exit(1);
    }
    // 9. Final Verification and Start
    await verifyAndStart();
}
//# sourceMappingURL=install.js.map