import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync } from "node:fs";
import { join } from "node:path";
// --- Directory Management ---
const EXTENSIONS_DIR = ".indusk/extensions";
const DISABLED_DIR = ".indusk/extensions/.disabled";
export function extensionsDir(projectRoot) {
    return join(projectRoot, EXTENSIONS_DIR);
}
export function disabledDir(projectRoot) {
    return join(projectRoot, DISABLED_DIR);
}
export function ensureExtensionsDirs(projectRoot) {
    mkdirSync(extensionsDir(projectRoot), { recursive: true });
    mkdirSync(disabledDir(projectRoot), { recursive: true });
}
// --- Loading ---
export function loadExtension(manifestPath) {
    try {
        const content = readFileSync(manifestPath, "utf-8");
        const manifest = JSON.parse(content);
        if (!manifest.name || !manifest.provides)
            return null;
        return manifest;
    }
    catch {
        return null;
    }
}
/**
 * Resolve the manifest path for an extension.
 * Supports both directory format ({name}/manifest.json) and legacy flat format ({name}.json).
 * Returns the path if found, null otherwise.
 */
export function resolveManifestPath(baseDir, name) {
    // Directory format first (preferred)
    const dirPath = join(baseDir, name, "manifest.json");
    if (existsSync(dirPath))
        return dirPath;
    // Legacy flat file
    const flatPath = join(baseDir, `${name}.json`);
    if (existsSync(flatPath))
        return flatPath;
    return null;
}
/**
 * Get the directory path for an extension (creates if needed).
 * This is where manifest.json, .env, and other extension files live.
 */
export function extensionConfigDir(projectRoot, name) {
    return join(extensionsDir(projectRoot), name);
}
/**
 * Migrate a flat file extension to directory format.
 * Moves {name}.json → {name}/manifest.json
 */
export function migrateToDirectory(baseDir, name) {
    const flatPath = join(baseDir, `${name}.json`);
    const dirPath = join(baseDir, name);
    const newPath = join(dirPath, "manifest.json");
    if (existsSync(flatPath) && !existsSync(newPath)) {
        mkdirSync(dirPath, { recursive: true });
        renameSync(flatPath, newPath);
    }
}
function loadFromDir(baseDir, enabled) {
    const extensions = [];
    if (!existsSync(baseDir))
        return extensions;
    const entries = readdirSync(baseDir, { withFileTypes: true });
    for (const entry of entries) {
        if (entry.name.startsWith("."))
            continue;
        let manifestPath = null;
        if (entry.isDirectory()) {
            // Directory format: {name}/manifest.json
            manifestPath = join(baseDir, entry.name, "manifest.json");
            if (!existsSync(manifestPath))
                continue;
        }
        else if (entry.isFile() && entry.name.endsWith(".json")) {
            // Legacy flat format: {name}.json — auto-migrate
            const name = entry.name.replace(".json", "");
            migrateToDirectory(baseDir, name);
            manifestPath = join(baseDir, name, "manifest.json");
            if (!existsSync(manifestPath)) {
                // Migration failed, read from flat file
                manifestPath = join(baseDir, entry.name);
            }
        }
        else {
            continue;
        }
        const manifest = loadExtension(manifestPath);
        if (manifest) {
            extensions.push({ manifest, path: manifestPath, enabled });
        }
    }
    return extensions;
}
export function loadExtensions(projectRoot) {
    const dir = extensionsDir(projectRoot);
    const disDir = disabledDir(projectRoot);
    return [...loadFromDir(dir, true), ...loadFromDir(disDir, false)];
}
export function getEnabledExtensions(projectRoot) {
    return loadExtensions(projectRoot).filter((e) => e.enabled);
}
// --- Enable / Disable ---
export function enableExtension(projectRoot, name) {
    const enDir = join(extensionsDir(projectRoot), name);
    const enManifest = join(enDir, "manifest.json");
    // Already enabled (directory format)
    if (existsSync(enManifest))
        return true;
    // Already enabled (legacy flat — migrate first)
    const enFlat = join(extensionsDir(projectRoot), `${name}.json`);
    if (existsSync(enFlat)) {
        migrateToDirectory(extensionsDir(projectRoot), name);
        return true;
    }
    // Check disabled — directory format
    const disDir = join(disabledDir(projectRoot), name);
    if (existsSync(join(disDir, "manifest.json"))) {
        renameSync(disDir, enDir);
        return true;
    }
    // Check disabled — legacy flat
    const disFlat = join(disabledDir(projectRoot), `${name}.json`);
    if (existsSync(disFlat)) {
        mkdirSync(enDir, { recursive: true });
        renameSync(disFlat, enManifest);
        return true;
    }
    return false; // Not found
}
export function disableExtension(projectRoot, name) {
    const enDir = join(extensionsDir(projectRoot), name);
    const disDir = join(disabledDir(projectRoot), name);
    if (existsSync(join(enDir, "manifest.json"))) {
        ensureExtensionsDirs(projectRoot);
        renameSync(enDir, disDir);
        return true;
    }
    // Legacy flat
    const enFlat = join(extensionsDir(projectRoot), `${name}.json`);
    if (existsSync(enFlat)) {
        ensureExtensionsDirs(projectRoot);
        mkdirSync(disDir, { recursive: true });
        renameSync(enFlat, join(disDir, "manifest.json"));
        return true;
    }
    return false;
}
// --- Query ---
export function isEnabled(projectRoot, name) {
    return (existsSync(join(extensionsDir(projectRoot), name, "manifest.json")) ||
        existsSync(join(extensionsDir(projectRoot), `${name}.json`)));
}
export function getExtension(projectRoot, name) {
    const enPath = resolveManifestPath(extensionsDir(projectRoot), name);
    if (enPath) {
        const manifest = loadExtension(enPath);
        return manifest ? { manifest, path: enPath, enabled: true } : null;
    }
    const disPath = resolveManifestPath(disabledDir(projectRoot), name);
    if (disPath) {
        const manifest = loadExtension(disPath);
        return manifest ? { manifest, path: disPath, enabled: false } : null;
    }
    return null;
}
