import { existsSync, lstatSync, mkdirSync, readdirSync, rmSync, symlinkSync, unlinkSync, } from 'node:fs';
import { join, relative } from 'node:path';
import { composeContent, generateHeader } from '../domain/composer.js';
import { readContextFile } from '../domain/reader.js';
import { copyConfigFiles } from '../domain/templates.js';
import { PROVIDER_CONFIGS } from '../domain/types.js';
const RESOURCE_DIRS = ['skills', 'agents', 'commands'];
/** Base adapter with shared symlink logic; subclasses override `generate()` for provider-specific output. */
export class BaseAdapter {
    copyConfigFiles(contextDir, dryRun) {
        return copyConfigFiles(this.providerName, contextDir, dryRun);
    }
    createSymlinks(context, rootDir, dryRun) {
        const config = PROVIDER_CONFIGS[this.providerName];
        const providerDir = join(context.contextDir, config.skillsDir);
        const created = [];
        if (context.isRoot) {
            for (const dir of RESOURCE_DIRS) {
                if ((dir === 'skills' && !context.hasSkills) ||
                    (dir === 'agents' && !context.hasAgents) ||
                    (dir === 'commands' && !context.hasCommands)) {
                    continue;
                }
                const target = join(context.aiDir, dir);
                const link = join(providerDir, dir);
                created.push(...this.ensureSymlink(link, target, context.contextDir, dryRun));
            }
        }
        else {
            for (const dir of RESOURCE_DIRS) {
                const contextResDir = join(context.aiDir, dir);
                const rootResDir = join(rootDir, '.ai', dir);
                const providerResDir = join(providerDir, dir);
                const hasContextDir = existsSync(contextResDir);
                const hasRootDir = existsSync(rootResDir);
                if (!hasContextDir && !hasRootDir)
                    continue;
                created.push(...this.createMergedSymlinks({
                    baseDir: context.contextDir,
                    contextDir: contextResDir,
                    dryRun,
                    providerDir: providerResDir,
                    rootDir: rootResDir,
                }));
            }
        }
        return created;
    }
    ensureSymlink(link, target, baseDir, dryRun) {
        const relTarget = relative(join(link, '..'), target);
        const relLink = relative(baseDir, link);
        if (dryRun) {
            return [`[dry-run] ${relLink} -> ${relTarget}`];
        }
        if (this.isSymlink(link)) {
            unlinkSync(link);
        }
        else if (existsSync(link)) {
            rmSync(link, { force: true, recursive: true });
        }
        const parentDir = join(link, '..');
        mkdirSync(parentDir, { recursive: true });
        symlinkSync(relTarget, link);
        return [`${relLink} -> ${relTarget}`];
    }
    generate(context, rootDir) {
        const config = PROVIDER_CONFIGS[this.providerName];
        const template = readContextFile(context);
        const composed = composeContent(template, config);
        const contextRelPath = relative(rootDir, context.contextFile);
        const header = generateHeader(contextRelPath, this.providerName);
        const outputPath = join(context.contextDir, config.instructionFile);
        const content = header + composed.trimEnd() + '\n';
        return [{ content, path: outputPath, type: 'instruction' }];
    }
    createMergedSymlinks(opts) {
        const { baseDir, contextDir, dryRun, providerDir, rootDir } = opts;
        const created = [];
        if (dryRun) {
            created.push(`[dry-run] mkdir ${providerDir}`);
        }
        else {
            rmSync(providerDir, { force: true, recursive: true });
            mkdirSync(providerDir, { recursive: true });
        }
        const contextEntries = existsSync(contextDir)
            ? readdirSync(contextDir, { withFileTypes: true })
                .filter((e) => e.isDirectory())
                .map((e) => e.name)
            : [];
        const rootEntries = existsSync(rootDir)
            ? readdirSync(rootDir, { withFileTypes: true })
                .filter((e) => e.isDirectory())
                .map((e) => e.name)
            : [];
        const contextSet = new Set(contextEntries);
        for (const name of contextEntries) {
            const target = join(contextDir, name);
            const link = join(providerDir, name);
            created.push(...this.ensureSymlink(link, target, baseDir, dryRun));
        }
        for (const name of rootEntries) {
            if (contextSet.has(name))
                continue;
            const target = join(rootDir, name);
            const link = join(providerDir, name);
            created.push(...this.ensureSymlink(link, target, baseDir, dryRun));
        }
        return created;
    }
    isSymlink(p) {
        try {
            return lstatSync(p).isSymbolicLink();
        }
        catch {
            return false;
        }
    }
}
