'use strict';

/* eslint-disable newline-per-chained-call */
const Promise = require('bluebird');
const bhttp = require('bhttp');
const { CookieJar } = Promise.promisifyAll(require('tough-cookie'));
const cheerio = require('cheerio');
const moment = require('moment');

const { cookieToData } = require('../utils/cookies');

function getThumbs(scene) {
    if (scene.images.poster) {
        return scene.images.poster.map(image => image.xl.url);
    }

    if (scene.images.card_main_rect) {
        return scene.images.card_main_rect
            .concat(scene.images.card_secondary_rect || [])
            .map(image => image.xl.url.replace('.thumb', ''));
    }

    return [];
}

async function scrapeLatest(items, site) {
    return Promise.all(items.map(async (data) => {
        const { id: entryId, title, description } = data;
        const url = `https://www.realitykings.com/scene/${entryId}/`;
        const date = new Date(data.dateReleased);
        const actors = data.actors.map(actor => actor.name);

        const tags = data.tags.map(tag => tag.name);

        const [poster, ...photos] = getThumbs(data);
        const trailer = data.videos.mediabook && (data.videos.mediabook.files['720p'] || data.videos.mediabook.files['320p']);
        const duration = data.videos.mediabook && data.videos.mediabook.length;

        return {
            url,
            entryId,
            title,
            description,
            actors,
            tags,
            duration,
            poster,
            photos,
            trailer: trailer && {
                src: trailer.urls.view,
                quality: parseInt(trailer.format, 10),
            },
            date,
            site,
        };
    }));
}

function scrapeLatestClassic(html, site) {
    const $ = cheerio.load(html, { normalizeWhitespace: true });

    const stateTag = $('script:contains("initialState")').html();
    const prefix = 'initialState = {';
    const prefixIndex = stateTag.indexOf('initialState = {');
    const suffix = '};';
    const stateString = stateTag.slice(prefixIndex + prefix.length - 1, stateTag.indexOf('};', prefixIndex) + suffix.length - 1);
    const data = JSON.parse(stateString);

    return Object.values(data.entities.releases).map((scene) => {
        const release = { site };

        release.entryId = scene.id;
        release.url = `${site.url}/scene/${release.entryId}/`;

        release.title = scene.title;
        release.description = scene.description;
        release.date = new Date(scene.dateReleased);

        release.actors = scene.actors.map(actorId => data.entities.actors[actorId].name);
        release.tags = scene.tags.map(tagId => data.entities.tags[tagId].name);

        const [poster, ...photos] = getThumbs(scene);

        release.poster = poster;
        release.photos = photos;

        if (scene.videos.mediabook) {
            const trailer = (scene.videos.mediabook.files['720p'] || scene.videos.mediabook.files['320p']);

            release.duration = scene.videos.mediabook.length;
            release.trailer = trailer && {
                src: trailer.urls.view,
                quality: parseInt(trailer.format, 10),
            };
        }

        return release;
    });
}

async function scrapeScene(data, url, site) {
    const { id: entryId, title, description } = data;
    const date = new Date(data.dateReleased);
    const actors = data.actors.map(actor => actor.name);

    const tags = data.tags.map(tag => tag.name);

    const [poster, ...photos] = getThumbs(data);
    const trailer = data.videos.mediabook && (data.videos.mediabook.files['720p'] || data.videos.mediabook.files['320p']);

    const siteName = data.collections[0].name;
    // const siteId = data.collections[0].id;
    const channel = siteName.replace(/\s+/g, '').toLowerCase();
    // const siteUrl = `https://www.realitykings.com/scenes?site=${siteId}`;

    return {
        url,
        entryId,
        title,
        description,
        actors,
        tags,
        poster,
        photos,
        trailer: trailer && {
            src: trailer.urls.view,
            quality: parseInt(trailer.format, 10),
        },
        date,
        site,
        channel,
    };
}

function getUrl(site) {
    const { hostname, search } = new URL(site.url);

    if (hostname.match(/(www\.)?realitykings\.com/) && search.match(/\?site=\d+/)) {
        return site.url;
    }

    if (site.parameters && site.parameters.siteId) {
        return `https://www.realitykings.com/scenes?site=${site.parameters.siteId}`;
    }

    throw new Error(`Reality Kings site '${site.name}' (${site.url}) not supported`);
}

async function fetchClassic(site, page) {
    const res = await bhttp.get(`${site.url}/scenes?page=${page}`);

    if (res.statusCode === 200) {
        return scrapeLatestClassic(res.body.toString(), site);
    }

    return null;
}

async function fetchLatest(site, page = 1) {
    if (site.parameters && site.parameters.classic) {
        return fetchClassic(site, page);
    }

    const url = getUrl(site);
    const { search } = new URL(url);
    const siteId = new URLSearchParams(search).get('site');

    const cookieJar = new CookieJar();
    const session = bhttp.session({ cookieJar });

    await session.get(url);

    const cookieString = await cookieJar.getCookieStringAsync(url);
    const { instance_token: instanceToken } = cookieToData(cookieString);

    const beforeDate = moment().add('1', 'day').format('YYYY-MM-DD');
    const limit = 10;
    const apiUrl = `https://site-api.project1service.com/v2/releases?collectionId=${siteId}&dateReleased=<${beforeDate}&limit=${limit}&offset=${limit * (page - 1)}&orderBy=-dateReleased&type=scene`;
    const res = await session.get(apiUrl, {
        headers: {
            Instance: instanceToken,
        },
    });

    return scrapeLatest(res.body.result, site);
}

async function fetchScene(url, site) {
    const entryId = url.match(/\d+/)[0];

    const cookieJar = new CookieJar();
    const session = bhttp.session({ cookieJar });

    await session.get(url);

    const cookieString = await cookieJar.getCookieStringAsync(url);
    const { instance_token: instanceToken } = cookieToData(cookieString);

    const res = await session.get(`https://site-api.project1service.com/v2/releases/${entryId}`, {
        headers: {
            Instance: instanceToken,
        },
    });

    return scrapeScene(res.body.result, url, site);
}

module.exports = {
    fetchLatest,
    fetchScene,
};
