import { readFile } from 'node:fs/promises';
import { existsSync, readdirSync, statSync } from 'node:fs';
import { resolve } from 'node:path';
import chalk from 'chalk';
import { getTemplatesRoot } from './templates.js';
import { DEFAULT_FRAMEWORK } from './constants.js';
import { readFileHelper } from './file-helper.js';
function isDirectory(path) {
    return statSync(path).isDirectory();
}
function findFilesRecursively(path, files) {
    const dirFiles = readdirSync(path);
    for (const file of dirFiles) {
        const filePath = resolve(path, file);
        if (isDirectory(filePath)) {
            findFilesRecursively(filePath, files);
        }
        else {
            files[filePath] = readFileHelper(filePath);
        }
    }
}
export async function getAllAddOns(framework, template) {
    const addOns = [];
    for (const type of ['add-on', 'example']) {
        const addOnsBase = resolve(getTemplatesRoot(), framework, type);
        if (!existsSync(addOnsBase)) {
            continue;
        }
        for (const dir of await readdirSync(addOnsBase).filter((file) => isDirectory(resolve(addOnsBase, file)))) {
            const filePath = resolve(addOnsBase, dir, 'info.json');
            const fileContent = await readFile(filePath, 'utf-8');
            const info = JSON.parse(fileContent);
            if (!info.templates.includes(template)) {
                continue;
            }
            let packageAdditions = {};
            if (existsSync(resolve(addOnsBase, dir, 'package.json'))) {
                packageAdditions = JSON.parse(await readFile(resolve(addOnsBase, dir, 'package.json'), 'utf-8'));
            }
            let readme;
            if (existsSync(resolve(addOnsBase, dir, 'README.md'))) {
                readme = await readFile(resolve(addOnsBase, dir, 'README.md'), 'utf-8');
            }
            const absoluteFiles = {};
            const assetsDir = resolve(addOnsBase, dir, 'assets');
            if (existsSync(assetsDir)) {
                await findFilesRecursively(assetsDir, absoluteFiles);
            }
            const files = {};
            for (const file of Object.keys(absoluteFiles)) {
                files[file.replace(assetsDir, '.')] = absoluteFiles[file];
            }
            addOns.push({
                ...info,
                id: dir,
                type,
                packageAdditions,
                readme,
                files,
                deletedFiles: [],
            });
        }
    }
    return addOns;
}
// Turn the list of chosen add-on IDs into a final list of add-ons by resolving dependencies
export async function finalizeAddOns(framework, template, chosenAddOnIDs) {
    const finalAddOnIDs = new Set(chosenAddOnIDs);
    const addOns = await getAllAddOns(framework, template);
    for (const addOnID of finalAddOnIDs) {
        let addOn;
        const localAddOn = addOns.find((a) => a.id === addOnID);
        if (localAddOn) {
            addOn = loadAddOn(localAddOn);
        }
        else if (addOnID.startsWith('http')) {
            addOn = await loadRemoteAddOn(addOnID);
            addOns.push(addOn);
        }
        else {
            throw new Error(`Add-on ${addOnID} not found`);
        }
        for (const dependsOn of addOn.dependsOn || []) {
            const dep = addOns.find((a) => a.id === dependsOn);
            if (!dep) {
                throw new Error(`Dependency ${dependsOn} not found`);
            }
            finalAddOnIDs.add(dep.id);
        }
    }
    const finalAddOns = [...finalAddOnIDs].map((id) => addOns.find((a) => a.id === id));
    return finalAddOns;
}
export async function listAddOns(options, { forcedMode, forcedAddOns = [], }) {
    const addOns = await getAllAddOns(options.framework || DEFAULT_FRAMEWORK, forcedMode || options.template || 'typescript');
    for (const addOn of addOns.filter((a) => !forcedAddOns.includes(a.id))) {
        console.log(`${chalk.bold(addOn.id)}: ${addOn.description}`);
    }
}
function loadAddOn(addOn) {
    return addOn;
}
export async function loadRemoteAddOn(url) {
    const response = await fetch(url);
    const fileContent = await response.json();
    fileContent.id = url;
    return fileContent;
}
