import { existsSync, writeFileSync } from 'node:fs';
import { relative } from 'node:path';
export class AiSetupService {
    ports;
    constructor(ports) {
        this.ports = ports;
    }
    async execute(options) {
        const { contexts, dryRun = false, force = false, rootDir } = options;
        const providers = await this.resolveProviders(options);
        if (providers.length === 0) {
            return {
                configsCopied: 0,
                filesWritten: 0,
                messages: ['No providers selected.'],
                symlinksCreated: 0,
            };
        }
        const messages = [];
        let configsCopied = 0;
        let filesWritten = 0;
        let symlinksCreated = 0;
        for (const providerName of providers) {
            const generator = this.ports.generators.get(providerName);
            if (!generator)
                continue;
            messages.push(`\n[${providerName}]`);
            for (const context of contexts) {
                // eslint-disable-next-line no-await-in-loop
                const result = await this.processContext({
                    context,
                    dryRun,
                    force,
                    generator,
                    messages,
                    rootDir,
                });
                configsCopied += result.configs;
                filesWritten += result.files;
                symlinksCreated += result.symlinks;
            }
        }
        messages.push('', `${providers.length} provider(s) x ${contexts.length} context(s) = ${filesWritten} files + ${symlinksCreated} symlinks + ${configsCopied} configs`);
        return { configsCopied, filesWritten, messages, symlinksCreated };
    }
    async processContext(params) {
        const { context, dryRun, force, generator, messages, rootDir } = params;
        let files = 0;
        for (const file of generator.generate(context, rootDir)) {
            if (file.type !== 'instruction' || !file.content)
                continue;
            const relPath = relative(rootDir, file.path);
            if (!dryRun && !force && existsSync(file.path)) {
                // eslint-disable-next-line no-await-in-loop
                const shouldOverwrite = await this.ports.prompt.confirmOverwrite([
                    relPath,
                ]);
                if (!shouldOverwrite) {
                    messages.push(`  ${context.name}: skipped ${relPath} (existing)`);
                    continue;
                }
            }
            if (dryRun) {
                messages.push(`  ${context.name}: [dry-run] ${relPath}`);
            }
            else {
                writeFileSync(file.path, file.content, 'utf8');
                messages.push(`  ${context.name}: ${relPath}`);
            }
            files++;
        }
        const symlinks = generator.createSymlinks(context, rootDir, dryRun);
        for (const s of symlinks) {
            messages.push(`  ${context.name}: ${s}`);
        }
        let configs = 0;
        if (context.isRoot) {
            const configResults = generator.copyConfigFiles(context.contextDir, dryRun);
            configs = configResults.length;
            for (const c of configResults) {
                messages.push(`  ${context.name}: config ${c}`);
            }
        }
        return { configs, files, symlinks: symlinks.length };
    }
    async resolveProviders(options) {
        const allProviders = [...this.ports.generators.keys()];
        if (options.all)
            return allProviders;
        if (options.providers && options.providers.length > 0)
            return options.providers;
        return this.ports.prompt.selectProviders(allProviders);
    }
}
