"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.MinecraftClientDownloader = void 0;
/**
 * @author NovaStepStudios
 * @alias StepnickaSantiago
 * @license Apache-2.0
 * @link https://www.apache.org/licenses/LICENSE-2.0
 */
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const https_1 = __importDefault(require("https"));
const events_1 = require("events");
class MinecraftClientDownloader extends events_1.EventEmitter {
    root;
    version;
    versionsDir;
    constructor(root, version) {
        super();
        this.root = root;
        this.version = version;
        this.versionsDir = path_1.default.join(root, "versions", version);
    }
    async start() {
        try {
            await this.ensureDir(this.versionsDir);
            const manifest = await this.fetchJSON("https://piston-meta.mojang.com/mc/game/version_manifest_v2.json");
            const versionMeta = manifest.versions.find((v) => v.id === this.version);
            if (!versionMeta)
                throw new Error(`[Version] Versión ${this.version} no encontrada.`);
            const versionJSON = await this.fetchJSON(versionMeta.url);
            const versionJSONPath = path_1.default.join(this.versionsDir, `${this.version}.json`);
            await fs_1.default.promises.writeFile(versionJSONPath, JSON.stringify(versionJSON, null, 2));
            this.emitProgress(1, 3);
            const clientURL = versionJSON.downloads?.client?.url;
            if (!clientURL)
                throw new Error(`[Not Found Client] No se encontró el cliente para ${this.version}`);
            const clientJarPath = path_1.default.join(this.versionsDir, `${this.version}.jar`);
            if (!fs_1.default.existsSync(clientJarPath)) {
                await this.downloadFile(clientURL, clientJarPath, (downloadedBytes, totalBytes) => {
                    const safeTotal = totalBytes > 0 ? totalBytes : 1;
                    const percentFile = (downloadedBytes / safeTotal) * 100;
                    const overallPercent = 33.33 + (percentFile / 3);
                    this.emit("progress", {
                        current: 2,
                        total: 3,
                        percent: overallPercent.toFixed(2),
                    });
                });
            }
            else {
                this.emitProgress(2, 3);
            }
            this.emitProgress(3, 3);
            this.emit("done");
        }
        catch (err) {
            this.emit("error", err);
        }
    }
    async fetchJSON(url) {
        return new Promise((resolve, reject) => {
            https_1.default.get(url, res => {
                if (res.statusCode !== 200)
                    return reject(new Error(`[HTTP Request] HTTP ${res.statusCode} - ${url}`));
                let data = "";
                res.on("data", chunk => data += chunk);
                res.on("end", () => {
                    try {
                        resolve(JSON.parse(data));
                    }
                    catch (err) {
                        reject(err);
                    }
                });
            }).on("error", reject);
        });
    }
    async downloadFile(url, dest, onProgress) {
        await fs_1.default.promises.mkdir(path_1.default.dirname(dest), { recursive: true });
        return new Promise((resolve, reject) => {
            const file = fs_1.default.createWriteStream(dest);
            https_1.default.get(url, res => {
                if (res.statusCode !== 200)
                    return reject(new Error(`[HTTP] Error HTTP: ${res.statusCode}`));
                const totalSize = parseInt(res.headers["content-length"] || "0", 10);
                let downloaded = 0;
                res.on("data", chunk => {
                    downloaded += chunk.length;
                    let percent = totalSize > 0 ? (downloaded / totalSize) * 100 : 0;
                    onProgress?.(downloaded, totalSize, percent);
                });
                res.pipe(file);
                file.on("finish", () => file.close(err => err ? reject(err) : resolve()));
                file.on("error", err => {
                    file.close();
                    fs_1.default.unlink(dest, () => { });
                    reject(err);
                });
            }).on("error", err => {
                fs_1.default.unlink(dest, () => { });
                reject(err);
            });
        });
    }
    async ensureDir(dir) {
        await fs_1.default.promises.mkdir(dir, { recursive: true });
    }
    emitProgress(current, total) {
        const safeCurrent = Number(current) || 0;
        const safeTotal = Number(total) || 1;
        const stepPercent = (safeCurrent / safeTotal) * 100;
        this.emit("progress", {
            current: safeCurrent,
            total: safeTotal,
            percent: stepPercent.toFixed(2),
        });
    }
}
exports.MinecraftClientDownloader = MinecraftClientDownloader;
