import axios from "axios";
import fs from "node:fs";
import path from "node:path";

export interface AssetMap {
    [originalUrl: string]: string;
}

export class AssetManager {
    private userAgent: string;

    constructor(userAgent: string = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36") {
        this.userAgent = userAgent;
    }

    public sanitizePath(rawPath: string): string {
        return rawPath
            .split("/")
            .map((p) => p.replace(/[^a-z0-9._-]/gi, "_"))
            .join("/");
    }

    public async downloadFile(url: string, assetsDir: string): Promise<string | null> {
        if (url.startsWith("//")) url = `https:${url}`;
        if (!url.startsWith("http")) return null;

        try {
            const u = new URL(url);
            const relPath = this.sanitizePath(u.hostname + u.pathname);
            const dest = path.join(assetsDir, relPath);

            if (fs.existsSync(dest)) return `./assets/${relPath}`;

            const res = await axios.get(url, {
                responseType: "arraybuffer",
                headers: { "User-Agent": this.userAgent },
                timeout: 15000,
                validateStatus: () => true,
            });

            if (res.status !== 200) return null;

            if (!fs.existsSync(path.dirname(dest)))
                fs.mkdirSync(path.dirname(dest), { recursive: true });
            fs.writeFileSync(dest, Buffer.from(res.data));
            return `./assets/${relPath}`;
        } catch {
            return null;
        }
    }

    public async processCssRecursively(
        cssContent: string,
        cssUrl: string,
        assetsDir: string,
        urlMap: AssetMap,
        depth = 0,
    ): Promise<string> {
        if (depth > 5) return cssContent;

        const urlRegex = /(?:url\(["']?|@import\s+["'])([^"'\)]+)["']?\)?/gi;
        let match;
        let newContent = cssContent;

        while ((match = urlRegex.exec(cssContent)) !== null) {
            const originalUrl = match[1];
            if (originalUrl.startsWith("data:") || originalUrl.startsWith("blob:"))
                continue;

            try {
                const absUrl = new URL(originalUrl, cssUrl).href;
                const local = await this.downloadFile(absUrl, assetsDir);

                if (local) {
                    const u = new URL(cssUrl);
                    const cssPath = u.hostname + u.pathname;
                    const assetPath = new URL(absUrl).hostname + new URL(absUrl).pathname;

                    const rel = path.relative(
                        path.dirname(this.sanitizePath(cssPath)),
                        this.sanitizePath(assetPath),
                    );

                    newContent = newContent.split(originalUrl).join(rel);
                    urlMap[absUrl] = local;
                }
            } catch {
                // Ignore
            }
        }
        return newContent;
    }
}
