import { xml2js } from "xml-js";
import { promises as fs } from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

export async function buildIcons(outputPath) {
    const iconPacksJson = await fs.readFile(path.resolve(__dirname, "./icon-packs.json"));
    const iconPacks = JSON.parse(iconPacksJson);

    const allIcons = [];

    for (const packName in iconPacks) {
        console.info(`Building icon pack "${packName}"`);

        const packConfig = iconPacks[packName];

        const prefix = packConfig["prefix"];
        const folder = packConfig["folder"];

        if (!prefix) {
            throw new Error(`"prefix" is not defined for icon pack "${packName}"`);
        }

        if (!folder) {
            throw new Error(`"folder" is not defined for icon pack "${packName}"`);
        }

        const folderPath = path.resolve(__dirname, folder);
        const files = await fs.readdir(folderPath);

        for (const fileName of files) {
            const icon = await loadIcon(folderPath, fileName, prefix);
            allIcons.push(icon);
        }
    }

    console.info(`Saving generated Icon Pack to: "${outputPath}"`);

    const allIconsJson = JSON.stringify(allIcons);
    await fs.writeFile(path.resolve(outputPath), allIconsJson);

    const md = makeMarkdown(allIcons);
    await fs.writeFile(path.resolve(__dirname, "all-icons.md"), md);

    console.info("Icons built successfully");
}

async function loadIcon(folderPath, fileName, prefix) {
    const segments = fileName.split(".");
    const type = segments[1];
    const name = segments[0];

    if (segments.length !== 3 || !["regular", "solid", "duotone"].includes(type) || !segments[2] === "svg") {
        throw new Error(
            `Failed to load icon "${fileName}". ` +
                'Icon files must be in the following format: "`name`.`type`.svg", where type is `regular`, `solid` or `duotone`',
        );
    }

    const fullPrefix = prefix + type[0];

    console.info(` - loading icon "${fullPrefix} ${name}" from file "${fileName}"`);

    const filePath = path.join(folderPath, fileName);

    const fileXML = await fs.readFile(filePath);
    const file = xml2js(fileXML);
    const svg = file.elements.find((e) => e.name === "svg");

    // icon without path / paths
    const icon = [parseInt(svg.attributes.width), parseInt(svg.attributes.height), [], ""];
    const paths = findAllPaths(svg);

    // duotone want array of paths, the others just a single path
    if (type === "duotone") {
        icon.push(paths);
    } else {
        icon.push(paths[0]);
    }

    return {
        iconName: name,
        prefix: fullPrefix,
        icon,
    };
}

function findAllPaths(element) {
    const childPaths = element.elements?.reduce((accumulator, e) => [...accumulator, ...findAllPaths(e)], []) ?? [];

    if (element.name === "path") {
        return [...childPaths, element.attributes.d];
    } else {
        return childPaths;
    }
}

function makeMarkdown(iconDefinitions) {
    let content = "# Icons\n\n";
    content += "Galaxy custom icons\n\n";
    content += "Auto-generated by `build_icons.js`\n\n";
    content += "## Usage\n\n";
    content += "```vue\n";
    content += "<script setup>\n";
    content += 'import { galaxyLogo } from "@/components/icons/galaxyIcons";\n';
    content += "</script>\n\n";
    content += "<template>\n";
    content += '    <FontAwesomeIcon :icon="galaxyLogo" />\n';
    content += "</template>\n";
    content += "```\n\n";
    content += "---\n\n";

    iconDefinitions.forEach((icon) => {
        content += `- **${icon.iconName}**: \`import { ${icon.iconName} } from "@/components/icons/galaxyIcons";\`\n`;
    });

    content += "\n---\n";

    return content;
}
