// import './bootloader.css';
import {Asset, Assets, ProgressCallback, Report} from "./types";

class Bootloader {
    private readonly assets: Assets;
    private readonly totalSize: number;
    private readonly progressMap: { [key: string]: number } = {};
    private readonly tagMap: { [key: string]: HTMLElement } = {};

    constructor(assets: Assets) {
        this.assets = assets;
        this.totalSize = Bootloader.getTotalSize(assets);
        console.log("TotalSize:", this.totalSize);
    }

    private static getTotalSize(assets: Assets): number {
        const cssAssets = assets.css || [];
        const jsAssets = assets.js || [];

        tag.id = id;
        tag.type = "text/javascript";
        tag.src = src;
        return tag;
    }


                    totalSize: this.totalSize,
                    loaded: this.getProgress(),
                });
            }, false);
            xhr.addEventListener("load", () => {
                const status = xhr.status;
                if (status === 200 || (status === 0 && xhr.response)) {
                    // is server does not support content-length header
                    this.updateProgress(asset.file, asset.size) &&

                const assetId = `asset_${asset.file}`;
                // remove asset if it exists
                const oldAsset = document.getElementById(assetId);
                oldAsset && document.head?.removeChild(oldAsset);
                // create new asset
                const objectURL = URL.createObjectURL(blob);
                const tag = js ? Bootloader.createScriptTag(objectURL, assetId) : Bootloader.createCssTag(objectURL, assetId);
                tag.onload = tag.onerror = () => {
                    // remove listeners
                    tag.onload = tag.onerror = null;
                    // note: if you want the file to be accessible after loading
                    // then comment out bellow line
                    URL.revokeObjectURL(objectURL);
                };
                this.tagMap[asset.file] = tag;

                return asset;
            });
    }

    private loadAssets(assets: Asset[], js: boolean, cb: ProgressCallback): Promise<Report> {
        const report: Report = {
            succeeded: [],
            failed: [],
        };
        const tasks = assets.map((asset) => this.loadAsset(asset, js, cb)
            .then((done) => {
                report.succeeded.push(done);
            })
            .catch((error) => {
                report.failed.push({asset, error});
            }));
        return Promise.all(tasks).then(() => report);
    }

    private mergeReport(lr1: Report, lr2: Report): void {
        lr2.succeeded.forEach((i) => lr1.succeeded.push(i));
        lr2.failed.forEach((i) => lr1.failed.push(i));
    }

    private appendHtmlElements(assets: Asset[]): void {
        for (const asset of assets) {
            const tag = this.tagMap[asset.file];
            if (tag) {
                document.head?.appendChild(tag);
            }
        }
    }

    public load(cb: ProgressCallback): Promise<Report> {
        const cssAssets = this.assets.css || [];
        const jsAssets = this.assets.js || [];

        const fullReport: Report = {
            succeeded: [],
            failed: [],
        };

        return this.loadAssets(cssAssets, false, cb)
            .then((report) => {
                this.mergeReport(fullReport, report);
                this.appendHtmlElements(cssAssets);
                return this.loadAssets(jsAssets, true, cb);
            })
            .then((report) => {
                this.mergeReport(fullReport, report);
                this.appendHtmlElements(jsAssets);
                return fullReport;
            });
    }
}

export function bootstrap() {
    const assets = window?.$bootloader?.assets || {};
    new Bootloader(assets)
        .load((e) => {
            const progress = (e.loaded / e.totalSize) * 100;
            const progressString = Math.floor(progress).toString() + "%";
            const progressBar = document.getElementById("progress_track");
            const progressValue = document.getElementById("progress_value");
            progressBar!.style.width = progressString;
            progressValue?.setAttribute("data-percent", progressString);
        }).then(() => {
        });
}

document.addEventListener("DOMContentLoaded", bootstrap);
