const { Source, RunnerScraper, Hoster } = require("source-scraper-core");
const { PuppeteerRunner } = require("source-scraper-puppeteer-runner");
const cheerio = require("cheerio");
const u = require("url");

class NinexbuddySource extends Source {
    constructor(source) {
        super(source);
        this.quality = source.quality;
    }
}

function parseSourceQuality(raw) {
    const ar1 = /^([a-zA-Z\d]+)\s*-\s*(\d+)([a-zA-Z]+)?$/i.exec(raw);
    if (ar1 !== null && ar1.length >= 4)
        return {
            raw,
            description: ar1[1],
            value: Number(ar1[2]),
            unit: ar1[3]
        };
    const ar2 = /^(\d+)([a-zA-Z]+)\s*\(?([a-zA-Z\s]+)\)?$/i.exec(raw);
    if (ar2 !== null && ar2.length >= 3)
        return {
            raw,
            description: ar2[3],
            value: Number(ar2[1]),
            unit: ar2[2]
        };
}

function parseHosterName(raw) {
    const ar = /^(?:embed\s*-)?\s*([a-zA-Z\d.]+)$/i.exec(raw.trim());
    if (ar === null || ar.length < 2)
        return;
    return ar[ar.length - 1];
}

function isDefined(value) {
    return typeof value !== 'undefined';
}

class NinexbuddyScraper extends RunnerScraper {
    constructor() {
        super();
        this.name = 'ninexbuddy';
        this.domains = [];
        this.urlPattern = /.*/i;
        this.runner = new PuppeteerRunner();
        this.defaultOptions = {
            runnerOptions: {
                navigationOptions: {
                    waitUntil: 'networkidle0'
                }
            }
        };
    }

    transformUrl(url) {
        return `https://9xbuddy.com/process?url=${url}`;
    }

    async execWithArgs({ page, url: ninexbuddyUrl }) {
        const isHoster = !!(await page.$('.playlist_el').catch(() => false));
        if (isHoster) {
            const items = await page.$$('.playlist_el .text-blue');
            const hosters = (await Promise.all(items.map(async (item) => {
                const urlPromise = item.getProperty('href').then(async (e) => e.jsonValue()).catch(() => undefined);
                const namePromise = item.getProperty('textContent').then(async (e) => e.jsonValue()).catch(() => undefined);
                const [url, name] = await Promise.all([urlPromise, namePromise]);
                const hosterUrl = u.parse(url, true).query.url;
                if (!hosterUrl)
                    return;
                const parsed = name ? parseHosterName(name) : undefined;
                if (!parsed)
                    return;
                return new Hoster({
                    url: hosterUrl,
                    name: parsed,
                });
            }))).filter(isDefined);
            return {
                ninexbuddyUrl,
                hosters
            };
        } else {
            const selector = '.tracking-wide.items-center.night-white';
            const items = await page.$$(selector);
            const sources = (await Promise.all(items.map(async (item) => {
                const formatPromise = item.$eval('.w-24.text-blue', e => e.textContent).catch(() => undefined);
                const qualityPromise = item.$eval('.w-1\\/2', e => e.textContent).catch(() => undefined);
                const urlPromise = item.$eval('.leading-normal.sm\\:leading-none', e => e.getAttribute('href')).catch(() => undefined);
                const [format, quality, url] = await Promise.all([formatPromise, qualityPromise, urlPromise]);
                if (!url)
                    return;
                return new NinexbuddySource({
                    url,
                    quality: quality ? parseSourceQuality(quality) : undefined,
                    type: format || undefined,
                    codec: undefined
                });
            }))).filter(isDefined);
            const poster = await page.$eval('img.shadow.border-2.border-grey-lighter.h-48', e => e.src).catch(() => undefined);
            return {
                ninexbuddyUrl,
                title: await page.title(),
                poster: poster && !poster.startsWith('data:image') ? poster : undefined,
                sources
            };
        }
    }
}

module.exports = {
    NinexbuddySource,
    NinexbuddyScraper
}