const path  = require('path'),
    package = require(path.resolve(__dirname, '../../package.json')),
    Error   = require(path.resolve(__dirname, './Error.js')),
    Image   = require(path.resolve(__dirname, './Image.js')),
    api     = require('ky-universal').create({
        prefixUrl: `https://r34.bulzyland.xyz/`,
        headers: {
            'User-Agent': `R34.js Client v${package.version}`
        }
    });

/**
 * Client for rule 34 api
 */

class R34 {
    
    /**
     * @property {Array} Api methods
     */

    constructor() {

       this.methods = [ 'random', 'search', 'tags', 'help' ];

    }

    /**
     * Help function
     * @param {String} method Name of the method you want to obtain information
     * @returns {Promise<Object>}
     */

    help(method) {
        
        return new Promise(async (resolve, reject) => {

            if(!method) return reject(new Error('You must enter the method you want to obtain information from'));
            if(!this.methods.includes(method.toLowerCase())) return reject(new Error('The method does not exist'));

            setImmediate(async () => {
                
                try {
                    
                    let res = await api.get('help').catch(e => e);
                    
                    let status = (res.response || res).status;
                    if(status >= 400) return resolve(JSON.parse(await res.response.text()));
                    
                    let json = await res.json();

                    if(!json.routes.hasOwnProperty(method.toLowerCase())) return reject(new Error('The method does not exist'));

                    resolve(json.routes[method.toLowerCase()]);

                } catch(e) {
                    return reject(new Error(e.toString()))
                } 

            })
        })

    }

    /**
     * Tags function
     * @param {Number} limit The limit of data you want to obtain (By default 1)
     * @returns {Promise<Object>}
     */

    tags(limit=1) {
        
        return new Promise(async (resolve, reject) => {

            if(typeof limit !== 'number') return reject(new Error('The limit must be a number'));
            limit = Math.round(limit);

            setImmediate(async () => {
                
                try {
                    
                    let res = await api.get('tags', {
                        searchParams: {
                            "limit": limit
                        }
                    }).catch(e => e);
                    
                    let status = (res.response || res).status;

                    resolve(status >= 400 ? JSON.parse(await res.response.text()) : await res.json());

                } catch(e) {
                    return reject(new Error(e.toString()))
                } 

            })
        })

    }

    /**
     * Random function
     * @param {Number} limit The limit of data you want to obtain (By default 1)
     * @param {String} type Format of the image you want to obtain (Optional)
     * @returns {Promise<Object>}
     */

    random(limit=1, type = false) {
        
        return new Promise(async (resolve, reject) => {

            if(typeof limit !== 'number') return reject(new Error('The limit must be a number'));
            limit = Math.round(limit);

            setImmediate(async () => {
                
                try {
                    
                    let params = {
                        "limit": limit
                    }

                    if(type) params['type'] = type;

                    let res = await api.get('random', {
                        searchParams: params
                    }).catch(e => e);
                    
                    let status = (res.response || res).status;
                    let json = status >= 400 ? JSON.parse(await res.response.text()) : await res.json();

                    if(status == 200) {
                        json.data = json.data.map(x => new Image(x))
                    }

                    resolve(json);

                } catch(e) {
                    return reject(new Error(e.toString()))
                } 

            })
        })

    }

    /**
     * Search function
     * @param {String} tag Tag from where you want to get an image
     * @returns {Promise<Object>}
     */

    search(tag) {
        
        return new Promise(async (resolve, reject) => {

            if(!tag) return reject(new Error('You need to enter a tag'));
            if(typeof tag !== 'string') return reject(new Error('The tag has to be a string'));

            setImmediate(async () => {
                
                try {
                    
                    let res = await api.get(`search/tag/${encodeURIComponent(tag)}`).catch(e => e);
                    
                    let status = (res.response || res).status;
                    let json = status >= 400 ? JSON.parse(await res.response.text()) : await res.json();

                    if(status == 200) {
                        json.data = new Image(json.data)
                    }

                    resolve(json)

                } catch(e) {
                    return reject(new Error(e.toString()))
                } 

            })
        })

    }

}

module.exports = R34;