/**
 * Config Command - Configuration management CLI command
 * Handles configuration operations: get, set, list, reset, edit, export
 */
import { BaseCommand } from '../BaseCommand.js';
import { ConfigManager } from '../config/ConfigManager.js';
import { ConfigValidator } from '../config/ConfigValidator.js';
import { ErrorHandler } from '../ErrorHandler.js';
import { PromptHelper } from '../PromptHelper.js';
import { Logger } from '../../config/logger.js';
import { isArray, isObject } from '../../helper/index.js';
import chalk from 'chalk';
const addOptions = (command) => {
    command.argument('[action]', 'Action: get, set, list, reset, edit, export');
    command.argument('[key]', 'Configuration key (for get/set)');
    command.argument('[value]', 'Configuration value (for set)');
    command.option('--global', 'Use global config instead of project config');
    command.option('--json', 'Output as JSON');
    command.option('--show-defaults', 'Show default values in list');
};
const getGlobalConfigManager = async () => ConfigManager.getGlobalConfig();
const getProjectConfigManager = async () => ConfigManager.getProjectConfig();
const toDisplayString = (value) => {
    if (value === undefined || value === null)
        return 'null';
    if (typeof value === 'string')
        return value;
    if (typeof value === 'number' || typeof value === 'bigint')
        return value.toString();
    if (typeof value === 'boolean')
        return value ? 'true' : 'false';
    if (typeof value === 'symbol')
        return value.toString();
    if (typeof value === 'function')
        return '[Function]';
    try {
        return JSON.stringify(value, null, 2);
    }
    catch {
        return '[Unserializable]';
    }
};
const formatConfigValue = (value) => {
    if (value === undefined || value === null)
        return chalk.gray('null');
    if (typeof value === 'object')
        return JSON.stringify(value, null, 2);
    if (typeof value === 'boolean')
        return value ? chalk.green('true') : chalk.red('false');
    if (typeof value === 'number')
        return chalk.yellow(value.toString());
    if (typeof value === 'string')
        return value;
    if (typeof value === 'bigint')
        return chalk.yellow(value.toString());
    if (typeof value === 'symbol')
        return chalk.gray(value.toString());
    if (typeof value === 'function')
        return chalk.gray('[Function]');
    return chalk.gray(toDisplayString(value));
};
const parseConfigValue = (value) => {
    if (value === undefined)
        return undefined;
    if (value === '')
        return '';
    const lower = value.toLowerCase();
    if (lower === 'true')
        return true;
    if (lower === 'false')
        return false;
    if (lower === 'null')
        return null;
    if (/^-?\d+$/.test(value))
        return Number.parseInt(value, 10);
    if (/^-?\d+\.\d+$/.test(value))
        return Number.parseFloat(value);
    if (value.startsWith('{') || value.startsWith('[')) {
        try {
            return JSON.parse(value);
        }
        catch (error) {
            Logger.error('Failed to parse JSON config value', error);
            return value;
        }
    }
    return value;
};
const displayValidationStatus = (cmd, config) => {
    const validation = ConfigValidator.validate(config);
    if (validation?.valid === true) {
        cmd.info(chalk.green('  ✅ Configuration is valid'));
        return;
    }
    const errors = validation?.errors ?? [];
    cmd.info(chalk.red(`  ❌ Configuration has ${errors.length} errors:`));
    for (const error of errors) {
        const message = error !== null && typeof error === 'object' && 'message' in error
            ? toDisplayString(error.message)
            : toDisplayString(error);
        cmd.info(chalk.red(`     - ${message}`));
    }
};
const displayConfigurationKeys = (cmd, keys) => {
    const sorted = keys.slice().sort((a, b) => a.localeCompare(b));
    cmd.info(chalk.cyan('\n  Available Keys:'));
    for (const key of sorted) {
        cmd.info(`  • ${key}`);
    }
};
const displayConfigurationValues = (cmd, config) => {
    cmd.info('');
    const entries = Object.entries(config).sort(([a], [b]) => a.localeCompare(b));
    for (const [key, value] of entries) {
        cmd.info(`${chalk.cyan(key)}: ${formatConfigValue(value)}`);
    }
};
const handleGet = (cmd, manager, key) => {
    if (key === undefined) {
        ErrorHandler.usageError('Configuration key is required for "get"');
    }
    if (typeof manager.get !== 'function') {
        cmd.warn('Configuration manager does not support "get"');
    }
    if (typeof manager.get === 'function' && key !== undefined) {
        const value = manager.get(key);
        if (value === undefined) {
            cmd.warn(`Configuration key "${key}" not found`);
        }
        cmd.info(formatConfigValue(value));
    }
};
const handleSet = (cmd, manager, key, value) => {
    if (key === undefined || value === undefined) {
        ErrorHandler.usageError('Both key and value are required for "set"');
        return;
    }
    if (typeof manager.set !== 'function') {
        cmd.warn('Configuration manager does not support "set"');
        return;
    }
    const parsedValue = parseConfigValue(value);
    const validationError = ConfigValidator.validateValue(key, parsedValue);
    if (validationError) {
        cmd.warn(`Validation error for "${key}": ${validationError.message}`);
        return;
    }
    manager.set(key, parsedValue);
    if (typeof manager.save === 'function') {
        manager.save();
    }
    cmd.success(`Configuration updated: ${key} = ${value}`);
};
const handleList = (cmd, manager, options) => {
    if (options['json'] === true && typeof manager.export === 'function') {
        cmd.info(manager.export());
    }
    const config = typeof manager.getConfig === 'function' ? manager.getConfig() : {};
    cmd.info(chalk.bold('\n🛠️  Current Configuration:\n'));
    displayValidationStatus(cmd, config);
    displayConfigurationKeys(cmd, Object.keys(config));
    displayConfigurationValues(cmd, config);
    if (options['showDefaults'] === true) {
        cmd.info(chalk.gray('\n(Default values shown above)'));
    }
};
const handleReset = async (cmd, manager) => {
    const confirmed = await PromptHelper.confirm('Are you sure you want to reset configuration to defaults?', false);
    if (!confirmed) {
        cmd.info('Reset cancelled');
        return;
    }
    if (typeof manager.reset === 'function') {
        manager.reset();
    }
    cmd.success('Configuration reset to defaults');
};
const editSingleConfig = async (cmd, manager, selectedKey) => {
    const currentValue = typeof manager.get === 'function' ? manager.get(selectedKey) : undefined;
    let defaultValue = '';
    if (currentValue !== undefined) {
        defaultValue =
            typeof currentValue === 'object'
                ? JSON.stringify(currentValue)
                : toDisplayString(currentValue);
    }
    const newValue = await PromptHelper.textInput(`Enter new value for "${selectedKey}":`, defaultValue);
    if (newValue === undefined)
        return;
    const parsedValue = parseConfigValue(newValue);
    const validationError = ConfigValidator.validateValue(selectedKey, parsedValue);
    if (validationError) {
        cmd.warn(`Validation error: ${validationError.message}`);
        return;
    }
    if (typeof manager.set === 'function') {
        manager.set(selectedKey, parsedValue);
    }
    if (typeof manager.save === 'function') {
        manager.save();
    }
    cmd.success(`Updated ${selectedKey}`);
};
const handleEdit = async (cmd, manager) => {
    cmd.info(chalk.bold('\n📝 Interactive Configuration Editor\n'));
    const config = typeof manager.getConfig === 'function' ? manager.getConfig() : {};
    const keys = Object.keys(config);
    const fallbackKeys = typeof manager.getAllKeys === 'function' ? manager.getAllKeys() : [];
    const availableKeys = keys.length > 0 ? keys : fallbackKeys;
    if (availableKeys.length === 0) {
        cmd.warn('No configuration keys found');
        return;
    }
    const menuKeys = [...availableKeys].sort((a, b) => a.localeCompare(b)).concat(['(Done)']);
    // Interactive prompt loop must be sequential.
    /* eslint-disable no-await-in-loop */
    while (true) {
        const selectedKey = await PromptHelper.chooseFrom('Select configuration key to edit:', menuKeys);
        if (selectedKey === '' || selectedKey === '(Done)')
            break;
        await editSingleConfig(cmd, manager, selectedKey);
    }
    /* eslint-enable no-await-in-loop */
    cmd.success('Configuration editing complete');
};
const handleExport = (cmd, manager) => {
    cmd.info(typeof manager.export === 'function' ? manager.export() : '{}');
};
const getArg = (args, index) => {
    if (!isArray(args))
        return undefined;
    const value = args[index];
    return typeof value === 'string' ? value : undefined;
};
const executeConfig = async (cmd, options) => {
    const typedCmd = cmd;
    const command = cmd.getCommand();
    const toRecord = (value) => {
        return isObject(value) ? value : {};
    };
    const commandOpts = typeof command.opts === 'function' ? toRecord(command.opts()) : {};
    const mergedOptions = {
        ...commandOpts,
        ...options,
    };
    const action = getArg(options.args, 0) ?? getArg(command.args, 0) ?? 'list';
    const key = getArg(options.args, 1) ?? getArg(command.args, 1);
    const value = getArg(options.args, 2) ?? getArg(command.args, 2);
    const manager = await typedCmd.getConfigManager(mergedOptions['global'] === true);
    await typedCmd.handleAction(action, manager, key, value, mergedOptions);
};
/**
 * Config Command Factory
 */
export const ConfigCommand = Object.freeze({
    /**
     * Create a new config command instance
     */
    create() {
        const cmd = BaseCommand.create({
            name: 'config',
            description: 'Manage application configuration',
            addOptions,
            execute: async (options) => executeConfig(cmd, options),
        });
        cmd.getConfigManager = async (isGlobal) => isGlobal ? getGlobalConfigManager() : getProjectConfigManager();
        cmd.handleGet = (manager, key, value) => handleGet(cmd, manager, key ?? value);
        cmd.handleSet = (manager, key, value) => handleSet(cmd, manager, key, value);
        cmd.handleList = (manager, options) => handleList(cmd, manager, options);
        cmd.handleReset = async (manager) => handleReset(cmd, manager);
        cmd.handleEdit = async (manager) => handleEdit(cmd, manager);
        cmd.handleExport = (manager) => handleExport(cmd, manager);
        cmd.handleAction = async (action, manager, key, value, options) => {
            switch (action.toLowerCase()) {
                case 'get':
                    cmd.handleGet(manager, key, value);
                    return;
                case 'set':
                    cmd.handleSet(manager, key, value, options);
                    return;
                case 'list':
                    cmd.handleList(manager, options ?? {});
                    return;
                case 'reset':
                    await cmd.handleReset(manager);
                    return;
                case 'edit':
                    await cmd.handleEdit(manager);
                    return;
                case 'export':
                    cmd.handleExport(manager);
                    return;
                default:
                    ErrorHandler.usageError(`Unknown action: ${action}`);
            }
        };
        cmd.parseConfigValue = (value) => parseConfigValue(value);
        cmd.formatConfigValue = (value) => formatConfigValue(value);
        cmd.displayValidationStatus = (config) => displayValidationStatus(cmd, config);
        cmd.displayConfigurationKeys = (keys) => displayConfigurationKeys(cmd, keys);
        cmd.displayConfigurationValues = (config) => displayConfigurationValues(cmd, config);
        cmd.editSingleConfig = async (manager, selectedKey) => editSingleConfig(cmd, manager, selectedKey);
        return cmd;
    },
});
