import os from 'node:os';
import path from 'node:path';
import { writeRawConfig } from '../../config.js';
import { pathsForImport, readExternalEntries } from '../../config-imports.js';
import { expandHome } from '../../env.js';
import { CliUsageError } from '../errors.js';
import { cloneConfig, loadOrCreateConfig } from './shared.js';
export async function handleAddCommand(options, args) {
    const name = args.shift();
    if (!name) {
        throw new CliUsageError('Usage: mcporter config add <name> [target]');
    }
    let positionalTarget;
    if (args[0] && !args[0].startsWith('--')) {
        positionalTarget = args.shift();
    }
    const flags = extractAddFlags(args);
    const targetPath = resolveWriteTarget(flags, options.loadOptions, options.loadOptions.rootDir ?? process.cwd());
    const effectiveLoadOptions = { ...options.loadOptions, configPath: targetPath };
    const { config, path: configPath } = await loadOrCreateConfig(effectiveLoadOptions);
    const nextConfig = cloneConfig(config);
    const baseEntry = await resolveBaseEntry(flags.copyFrom, options.loadOptions);
    const entry = baseEntry ? { ...baseEntry } : {};
    applyTargetToEntry(entry, positionalTarget, flags);
    applyFlagsToEntry(entry, flags);
    validateTransportChoice(entry, flags.transport);
    const hasHttpTarget = Boolean(entry.baseUrl) ||
        Boolean(entry.base_url) ||
        Boolean(entry.url) ||
        Boolean(entry.serverUrl) ||
        Boolean(entry.server_url);
    const hasCommandTarget = Boolean(entry.command ?? entry.executable);
    if (flags.args.length > 0 && !hasCommandTarget) {
        throw new CliUsageError('--arg requires a stdio command (use --command, --stdio, or provide a positional target).');
    }
    if (!hasHttpTarget && !hasCommandTarget) {
        throw new CliUsageError('Server definitions require either a --url/target or a stdio command.');
    }
    if (!nextConfig.mcpServers) {
        nextConfig.mcpServers = {};
    }
    nextConfig.mcpServers[name] = entry;
    if (flags.dryRun) {
        console.log(JSON.stringify({ [name]: entry }, null, 2));
        console.log('(dry-run) No changes were written.');
        return;
    }
    await writeRawConfig(configPath, nextConfig);
    console.log(`Added '${name}' to ${configPath}`);
}
export function resolveWriteTarget(flags, loadOptions, rootDir) {
    if (flags.persistPath) {
        return path.resolve(expandHome(flags.persistPath));
    }
    if (flags.scope === 'home') {
        return path.join(os.homedir(), '.mcporter', 'mcporter.json');
    }
    if (flags.scope === 'project') {
        return path.resolve(rootDir, 'config', 'mcporter.json');
    }
    if (loadOptions.configPath) {
        return path.resolve(expandHome(loadOptions.configPath));
    }
    return path.resolve(rootDir, 'config', 'mcporter.json');
}
function extractAddFlags(args) {
    const flags = { args: [], env: {}, headers: {} };
    let index = 0;
    while (index < args.length) {
        const token = args[index];
        switch (token) {
            case '--transport':
                flags.transport = parseTransport(requireValue(args, index, token));
                args.splice(index, 2);
                continue;
            case '--url':
                flags.url = requireValue(args, index, token);
                args.splice(index, 2);
                continue;
            case '--command':
                flags.command = requireValue(args, index, token);
                args.splice(index, 2);
                continue;
            case '--stdio':
                flags.stdio = requireValue(args, index, token);
                args.splice(index, 2);
                continue;
            case '--arg':
                flags.args.push(requireValue(args, index, token));
                args.splice(index, 2);
                continue;
            case '--description':
                flags.description = requireValue(args, index, token);
                args.splice(index, 2);
                continue;
            case '--env':
                parseKeyValue(requireValue(args, index, token), flags.env, '--env');
                args.splice(index, 2);
                continue;
            case '--header':
                parseKeyValue(requireValue(args, index, token), flags.headers, '--header');
                args.splice(index, 2);
                continue;
            case '--token-cache-dir':
                flags.tokenCacheDir = requireValue(args, index, token);
                args.splice(index, 2);
                continue;
            case '--client-name':
                flags.clientName = requireValue(args, index, token);
                args.splice(index, 2);
                continue;
            case '--oauth-redirect-url':
                flags.oauthRedirectUrl = requireValue(args, index, token);
                args.splice(index, 2);
                continue;
            case '--auth':
                flags.auth = requireValue(args, index, token);
                args.splice(index, 2);
                continue;
            case '--copy-from':
                flags.copyFrom = requireValue(args, index, token);
                args.splice(index, 2);
                continue;
            case '--persist':
                flags.persistPath = requireValue(args, index, token);
                args.splice(index, 2);
                continue;
            case '--scope': {
                const scopeValue = requireValue(args, index, token);
                if (scopeValue !== 'home' && scopeValue !== 'project') {
                    throw new CliUsageError('--scope must be either "home" or "project".');
                }
                flags.scope = scopeValue;
                args.splice(index, 2);
                continue;
            }
            case '--dry-run':
                flags.dryRun = true;
                args.splice(index, 1);
                continue;
            case '--':
                args.splice(index, 1);
                while (index < args.length) {
                    const value = args[index];
                    if (value !== undefined) {
                        flags.args.push(value);
                    }
                    args.splice(index, 1);
                }
                continue;
            default:
                index += 1;
                break;
        }
    }
    return flags;
}
function parseTransport(value) {
    if (value !== 'http' && value !== 'sse' && value !== 'stdio') {
        throw new CliUsageError("--transport must be one of 'http', 'sse', or 'stdio'.");
    }
    return value;
}
function parseKeyValue(input, target, flagName) {
    if (!input || !input.includes('=')) {
        throw new CliUsageError(`${flagName} requires KEY=value.`);
    }
    const [key, ...rest] = input.split('=');
    if (!key) {
        throw new CliUsageError(`${flagName} requires KEY=value.`);
    }
    target[key] = rest.join('=');
}
function requireValue(args, index, flagName) {
    const value = args[index + 1];
    if (!value) {
        throw new CliUsageError(`Flag '${flagName}' requires a value.`);
    }
    return value;
}
async function resolveBaseEntry(copyFrom, options) {
    if (!copyFrom) {
        return null;
    }
    const [kind, ...rest] = copyFrom.split(':');
    const name = rest.join(':');
    if (!kind || !name) {
        throw new CliUsageError("--copy-from requires the format '<import>:<name>'.");
    }
    const rootDir = options.rootDir ?? process.cwd();
    const paths = pathsForImport(kind, rootDir);
    for (const candidate of paths) {
        const resolved = expandHome(candidate);
        const entries = await readExternalEntries(resolved, { projectRoot: rootDir, importKind: kind });
        if (!entries) {
            continue;
        }
        const entry = entries.get(name);
        if (entry) {
            return structuredClone(entry);
        }
    }
    throw new CliUsageError(`Unable to find '${name}' in import '${kind}'.`);
}
function applyTargetToEntry(entry, positionalTarget, flags) {
    if (flags.url) {
        entry.baseUrl = flags.url;
        return;
    }
    if (flags.command) {
        entry.command = flags.command;
    }
    if (flags.stdio) {
        entry.command = flags.stdio;
    }
    if (positionalTarget) {
        if (looksLikeHttp(positionalTarget)) {
            entry.baseUrl = positionalTarget;
        }
        else {
            entry.command = positionalTarget;
        }
    }
}
function applyFlagsToEntry(entry, flags) {
    if (flags.args.length > 0) {
        entry.args = flags.args;
    }
    if (flags.description) {
        entry.description = flags.description;
    }
    if (Object.keys(flags.env).length > 0) {
        entry.env = entry.env ? { ...entry.env, ...flags.env } : { ...flags.env };
    }
    if (Object.keys(flags.headers).length > 0) {
        entry.headers = entry.headers ? { ...entry.headers, ...flags.headers } : { ...flags.headers };
    }
    if (flags.tokenCacheDir) {
        entry.tokenCacheDir = flags.tokenCacheDir;
    }
    if (flags.clientName) {
        entry.clientName = flags.clientName;
    }
    if (flags.oauthRedirectUrl) {
        entry.oauthRedirectUrl = flags.oauthRedirectUrl;
    }
    if (flags.auth) {
        entry.auth = flags.auth;
    }
}
function validateTransportChoice(entry, transport) {
    if (!transport) {
        return;
    }
    const isHttp = Boolean(entry.baseUrl ?? entry.url ?? entry.serverUrl);
    const isStdio = Boolean(entry.command ?? entry.args);
    if (transport === 'stdio' && !isStdio) {
        throw new CliUsageError("Transport 'stdio' requires a stdio command.");
    }
    if ((transport === 'http' || transport === 'sse') && !isHttp) {
        throw new CliUsageError(`Transport '${transport}' requires a URL target.`);
    }
}
function looksLikeHttp(value) {
    return value.startsWith('http://') || value.startsWith('https://');
}
//# sourceMappingURL=add.js.map