"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.WebtorrentAdapter = void 0;
const webtorrent_1 = __importDefault(require("webtorrent"));
const util_1 = require("util");
const fs_1 = require("fs");
const _1 = require(".");
class WebtorrentAdapter extends _1.TorrentAdapter {
    constructor() {
        super();
        this.client = new webtorrent_1.default();
    }
    async add(magnet, path) {
        await util_1.promisify(fs_1.mkdir)(path, { recursive: true });
        const torrent = this.client.add(magnet, {
            path,
        });
        return new Promise((resolve, reject) => {
            const timeout = setTimeout(() => {
                torrent.destroy({
                    destroyStore: true,
                }, () => {
                    if (torrent.numPeers === 0) {
                        reject(new _1.TorrentClientError('Timeout while loading torrent: no peers found'));
                    }
                    else {
                        reject(new _1.TorrentClientError('Timeout while loading torrent'));
                    }
                });
            }, 10 * 1000);
            torrent.on('error', (e) => {
                clearTimeout(timeout);
                if (String(e).includes('duplicate torrent')) {
                    const value = this.client.get(torrent.infoHash);
                    if (value) {
                        resolve(this.createTorrentFromClient(value));
                    }
                    else {
                        reject(e);
                    }
                }
                else {
                    reject(e);
                }
            });
            torrent.on('metadata', () => {
                torrent.deselect(0, torrent.pieces.length - 1, 0);
                torrent.files.forEach((file) => {
                    file.deselect();
                });
            });
            torrent.on('ready', () => {
                clearTimeout(timeout);
                resolve(this.createTorrentFromClient(torrent));
            });
        });
    }
    async destroy() {
        return new Promise((resolve, reject) => {
            this.client.destroy((err) => {
                if (err instanceof Error) {
                    reject(err);
                }
                else {
                    resolve();
                }
            });
        });
    }
    createTorrentFromClient(torrent) {
        return {
            name: torrent.name,
            files: torrent.files.map((file) => ({
                name: file.name,
                path: file.path,
                length: file.length,
                createReadStream(range) {
                    return file.createReadStream(range);
                },
                stop() {
                    file.deselect();
                },
            })),
            async remove() {
                new Promise((resolve, reject) => {
                    torrent.destroy({
                        destroyStore: true,
                    }, (err) => {
                        if (err instanceof Error) {
                            reject(err);
                        }
                        else {
                            resolve();
                        }
                    });
                });
            },
            getDownloadSpeed() {
                return torrent.downloadSpeed;
            },
            getDownloaded() {
                return torrent.downloaded;
            },
            getUploadSpeed() {
                return torrent.uploadSpeed;
            },
            getUploaded() {
                return torrent.uploaded;
            },
        };
    }
}
exports.WebtorrentAdapter = WebtorrentAdapter;
