import fs from 'node:fs/promises';
import path from 'node:path';
import { renderClientModule, renderTypesModule } from './emit-ts-templates.js';
import { extractGeneratorFlags } from './generate/flag-parser.js';
import { readPackageMetadata } from './generate/template.js';
import { extractHttpServerTarget } from './http-utils.js';
import { buildToolDoc } from './list-detail-helpers.js';
import { consumeOutputFormat } from './output-format.js';
import { findServerByHttpUrl } from './server-lookup.js';
import { loadToolMetadata } from './tool-cache.js';
export async function handleEmitTs(runtime, args) {
    const options = parseEmitTsArgs(args);
    const definition = getServerDefinition(runtime, options.server);
    const metadataEntries = await loadToolMetadata(runtime, options.server, {
        includeSchema: true,
        autoAuthorize: false,
    });
    const generator = await readPackageMetadata();
    const metadata = {
        server: definition,
        generatorLabel: `${generator.name}@${generator.version}`,
        generatedAt: new Date(),
    };
    const docEntries = buildDocEntries(options.server, metadataEntries, options.includeOptional);
    const interfaceName = buildInterfaceName(options.server);
    if (options.mode === 'types') {
        const source = renderTypesModule({ interfaceName, docs: docEntries, metadata });
        await writeFile(options.outPath, source);
        if (options.format === 'json') {
            console.log(JSON.stringify({
                mode: 'types',
                server: options.server,
                outPath: options.outPath,
            }, null, 2));
        }
        else {
            console.log(`Emitted TypeScript definitions for ${options.server} → ${options.outPath}`);
        }
        return;
    }
    const typesOutPath = options.typesOutPath ?? deriveTypesOutPath(options.outPath);
    const relativeImportPath = computeImportPath(options.outPath, typesOutPath);
    const typesSource = renderTypesModule({ interfaceName, docs: docEntries, metadata });
    const clientSource = renderClientModule({
        interfaceName,
        docs: docEntries,
        metadata,
        typesImportPath: relativeImportPath,
    });
    await writeFile(typesOutPath, typesSource);
    await writeFile(options.outPath, clientSource);
    if (options.format === 'json') {
        console.log(JSON.stringify({
            mode: 'client',
            server: options.server,
            clientOutPath: options.outPath,
            typesOutPath,
        }, null, 2));
    }
    else {
        console.log(`Emitted client + types for ${options.server} → ${options.outPath} / ${typesOutPath}`);
    }
}
function parseEmitTsArgs(args) {
    const flags = {
        mode: 'types',
        includeOptional: false,
        format: 'text',
    };
    const common = extractGeneratorFlags(args, { allowIncludeOptional: true });
    if (common.includeOptional) {
        flags.includeOptional = true;
    }
    flags.format = consumeOutputFormat(args, {
        defaultFormat: 'text',
        allowed: ['text', 'json'],
        enableRawShortcut: false,
        jsonShortcutFlag: '--json',
    });
    let index = 0;
    while (index < args.length) {
        const token = args[index];
        if (!token) {
            index += 1;
            continue;
        }
        if (token === '--out') {
            const value = args[index + 1];
            if (!value) {
                throw new Error("Flag '--out' requires a path.");
            }
            flags.outPath = value;
            args.splice(index, 2);
            continue;
        }
        if (token === '--types-out') {
            const value = args[index + 1];
            if (!value) {
                throw new Error("Flag '--types-out' requires a path.");
            }
            flags.typesOutPath = value;
            args.splice(index, 2);
            continue;
        }
        if (token === '--mode') {
            const value = args[index + 1];
            if (value !== 'types' && value !== 'client') {
                throw new Error("--mode must be 'types' or 'client'.");
            }
            flags.mode = value;
            args.splice(index, 2);
            continue;
        }
        if (token.startsWith('--')) {
            throw new Error(`Unknown flag '${token}' for emit-ts.`);
        }
        index += 1;
    }
    const server = args.shift();
    if (!server) {
        throw new Error('Usage: mcporter emit-ts <server> --out <file> [--mode types|client]');
    }
    const outPath = flags.outPath;
    if (!outPath) {
        throw new Error("Flag '--out' is required for emit-ts.");
    }
    if (flags.mode === 'client' && !outPath.endsWith('.ts')) {
        throw new Error('--out should point to a .ts file when --mode client is used.');
    }
    if (flags.mode === 'types' && !outPath.endsWith('.ts') && !outPath.endsWith('.d.ts')) {
        throw new Error('--out should be a .ts or .d.ts file for --mode types.');
    }
    return {
        server,
        outPath: path.resolve(outPath),
        mode: flags.mode,
        includeOptional: flags.includeOptional,
        typesOutPath: flags.typesOutPath ? path.resolve(flags.typesOutPath) : undefined,
        format: flags.format,
    };
}
function getServerDefinition(runtime, selector) {
    try {
        return runtime.getDefinition(selector);
    }
    catch (error) {
        const resolved = resolveHttpServerName(runtime, selector);
        if (resolved) {
            return runtime.getDefinition(resolved);
        }
        if (error instanceof Error) {
            throw new Error(error.message);
        }
        throw error;
    }
}
function resolveHttpServerName(runtime, selector) {
    const target = extractHttpServerTarget(selector);
    if (!target) {
        return undefined;
    }
    return findServerByHttpUrl(runtime.getDefinitions(), target);
}
function buildDocEntries(serverName, metadataEntries, includeOptional) {
    return metadataEntries.map((entry) => {
        const doc = buildToolDoc({
            serverName,
            toolName: entry.tool.name,
            description: entry.tool.description,
            outputSchema: entry.tool.outputSchema,
            options: entry.options,
            requiredOnly: !includeOptional,
            colorize: false,
            defaultReturnType: 'CallResult',
        });
        return {
            toolName: entry.tool.name,
            methodName: entry.methodName,
            doc,
        };
    });
}
function buildInterfaceName(serverName) {
    const cleaned = serverName
        .split(/[^A-Za-z0-9]+/)
        .filter(Boolean)
        .map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1))
        .join('');
    const base = cleaned.length > 0 ? cleaned : 'Server';
    return `${base}Tools`;
}
function deriveTypesOutPath(tsPath) {
    const dir = path.dirname(tsPath);
    const base = path.basename(tsPath, path.extname(tsPath));
    return path.join(dir, `${base}.d.ts`);
}
async function writeFile(targetPath, contents) {
    await fs.mkdir(path.dirname(targetPath), { recursive: true });
    await fs.writeFile(targetPath, `${contents}\n`, 'utf8');
}
function computeImportPath(fromPath, typesPath) {
    const fromDir = path.dirname(fromPath);
    const relative = path.relative(fromDir, typesPath).replace(/\\/g, '/');
    const withoutExt = relative.replace(/\.[^.]+$/, '');
    if (withoutExt.startsWith('.')) {
        return withoutExt;
    }
    return `./${withoutExt}`;
}
export const __test = {
    parseEmitTsArgs,
    buildInterfaceName,
    deriveTypesOutPath,
    computeImportPath,
    buildDocEntries,
};
//# sourceMappingURL=emit-ts-command.js.map