'use strict';


/**
 * Set to true for the following behavior:
 * - Request server to recognize using bleeding-edge models
 * - Reload FunCAPTCHA on verification
 */
export const IS_DEVELOPMENT = false;


/**
 * Trying to be an Enum but javascript doesn't have enums
 */
export class RunningAs {
    // Background script running on-demand
    static BACKGROUND = 'BACKGROUND';
    // Popup specified in manifest as "action"
    static POPUP = 'POPUP';
    // Content script running in page
    static CONTENT = 'CONTENT';
    // (somehow) Standalone run of script running in webpage
    static WEB = 'WEB';
}
Object.freeze(RunningAs);


export const runningAt = (() => {
    let getBackgroundPage = globalThis?.chrome?.extension?.getBackgroundPage;
    if (getBackgroundPage){
        return getBackgroundPage() === window ? RunningAs.BACKGROUND : RunningAs.POPUP;
    }
    return globalThis?.chrome?.runtime?.onMessage ? RunningAs.CONTENT : RunningAs.WEB;
})();


export function deep_copy(obj) {
    return JSON.parse(JSON.stringify(obj));
}


export class Util {
    static CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';

    static pad_left(s, char, n) {
        while (`${s}`.length < n) {
            s = `${char}${s}`;
        }
        return s;
    }

    static capitalize(s) {
        return s.charAt(0).toUpperCase() + s.slice(1);
    }

    static parse_int(s, fallback) {
        if (!s) {
            s = fallback;
        }
        return parseInt(s);
    }

    static parse_bool(s, fallback) {
        if (s === 'true') {
            s = true;
        }
        else if (s === 'false') {
            s = false;
        }
        else {
            s = fallback;
        }
        return s;
    }

    static parse_string(s, fallback) {
        if (!s) {
            s = fallback;
        }
        return s;
    }

    static parse_json(s, fallback) {
        if (!s) {
            s = fallback;
        }
        else {
            s = JSON.parse(s);
        }
        return s;
    }

    static generate_id(n) {
        let result = '';
        for (let i = 0; i < n; i++) {
            result += Util.CHARS.charAt(Math.floor(Math.random() * Util.CHARS.length));
        }
        return result;
    }
}


export class Time {
    static time() {
        if (!Date.now) {
            Date.now = () => new Date().getTime();
        }
        return Date.now();
    }

    static date() {
        return new Date();
    }

    static sleep(i=1000) {
        return new Promise(resolve => setTimeout(resolve, i));
    }

    static async random_sleep(min, max) {
        const duration = Math.floor(Math.random() * (max - min) + min);
        return await Time.sleep(duration);
    }

    static seconds_as_hms(t) {
        t = Math.max(0, t);
        const hours = Util.pad_left(Math.floor(t / 3600), '0', 2);
        t %= 3600;
        const minutes = Util.pad_left(Math.floor(t / 60), '0', 2);
        const seconds = Util.pad_left(Math.floor(t % 60), '0', 2);
        return `${hours}:${minutes}:${seconds}`;
    }

    static string(d=null) {
        if (!d) {
            d = Time.date();
        }
        const month = Util.pad_left(d.getMonth() + 1, '0', 2);
        const date = Util.pad_left(d.getDate(), '0', 2);
        const year = d.getFullYear();
        const hours = Util.pad_left(d.getHours() % 12, '0', 2);
        const minutes = Util.pad_left(d.getMinutes(), '0', 2);
        const seconds = Util.pad_left(d.getSeconds(), '0', 2);
        const period = d.getHours() >= 12 ? 'PM' : 'AM';
        return `${month}/${date}/${year} ${hours}:${minutes}:${seconds} ${period}`;
    }
}


export class SettingsManager {
    static DEFAULT = {
        version: 15,
        key: '',

        enabled: true,
        disabled_hosts: [],

        hcaptcha_auto_open: true,
        hcaptcha_auto_solve: true,
        hcaptcha_solve_delay: true,
        hcaptcha_solve_delay_time: 3000,

        recaptcha_auto_open: true,
        recaptcha_auto_solve: true,
        recaptcha_solve_delay: true,
        recaptcha_solve_delay_time: 2000,
        recaptcha_solve_method: 'Image',

        funcaptcha_auto_open: true,
        funcaptcha_auto_solve: true,
        funcaptcha_solve_delay: true,
        funcaptcha_solve_delay_time: 1000,

        awscaptcha_auto_open: true,
        awscaptcha_auto_solve: true,
        awscaptcha_solve_delay: true,
        awscaptcha_solve_delay_time: 1000,

        textcaptcha_auto_solve: true,
        textcaptcha_solve_delay: true,
        textcaptcha_solve_delay_time: 100,
        textcaptcha_image_selector: '',
        textcaptcha_input_selector: '',
    };

    static ENCODE_FIELDS = {
        enabled: {parse: Util.parse_bool, encode: encodeURIComponent},
        disabled_hosts: {parse: Util.parse_json, encode: e => encodeURIComponent(JSON.stringify(e))},

        hcaptcha_auto_open: {parse: Util.parse_bool, encode: encodeURIComponent},
        hcaptcha_auto_solve: {parse: Util.parse_bool, encode: encodeURIComponent},
        hcaptcha_solve_delay: {parse: Util.parse_bool, encode: encodeURIComponent},
        hcaptcha_solve_delay_time: {parse: Util.parse_int, encode: encodeURIComponent},

        recaptcha_auto_open: {parse: Util.parse_bool, encode: encodeURIComponent},
        recaptcha_auto_solve: {parse: Util.parse_bool, encode: encodeURIComponent},
        recaptcha_solve_delay: {parse: Util.parse_bool, encode: encodeURIComponent},
        recaptcha_solve_delay_time: {parse: Util.parse_int, encode: encodeURIComponent},
        recaptcha_solve_method: {parse: Util.parse_string, encode: encodeURIComponent},

        funcaptcha_auto_open: {parse: Util.parse_bool, encode: encodeURIComponent},
        funcaptcha_auto_solve: {parse: Util.parse_bool, encode: encodeURIComponent},
        funcaptcha_solve_delay: {parse: Util.parse_bool, encode: encodeURIComponent},
        funcaptcha_solve_delay_time: {parse: Util.parse_int, encode: encodeURIComponent},

        awscaptcha_auto_open: {parse: Util.parse_bool, encode: encodeURIComponent},
        awscaptcha_auto_solve: {parse: Util.parse_bool, encode: encodeURIComponent},
        awscaptcha_solve_delay: {parse: Util.parse_bool, encode: encodeURIComponent},
        awscaptcha_solve_delay_time: {parse: Util.parse_int, encode: encodeURIComponent},

        textcaptcha_auto_solve: {parse: Util.parse_bool, encode: encodeURIComponent},
        textcaptcha_solve_delay: {parse: Util.parse_bool, encode: encodeURIComponent},
        textcaptcha_solve_delay_time: {parse: Util.parse_int, encode: encodeURIComponent},
        textcaptcha_image_selector: {parse: Util.parse_string, encode: encodeURIComponent},
        textcaptcha_input_selector: {parse: Util.parse_string, encode: encodeURIComponent},
    };

    static IMPORT_URL = 'https://nopecha.com/setup';
    static DELIMITER = '|';

    static export(settings) {
        if (!settings.key) {
            return false;
        }

        const fields = [settings.key];
        for (const k in SettingsManager.ENCODE_FIELDS) {
            fields.push(`${k}=${SettingsManager.ENCODE_FIELDS[k].encode(settings[k])}`);
        }

        const encoded_hash = `#${fields.join(SettingsManager.DELIMITER)}`;

        return `${SettingsManager.IMPORT_URL}${encoded_hash}`;
    }

    static import(encoded_hash) {
        const settings = {};

        // Split by delimiter
        const fields = encoded_hash.split(SettingsManager.DELIMITER);
        if (fields.length === 0) {
            return settings;
        }

        // Parse key
        const key = fields.shift();
        if (key.length <= 1) {
            console.error('invalid key for settings', key);
            return settings;
        }
        settings.key = key.substring(1);

        // Parse additional fields
        for (const field of fields) {
            const kv = field.split('=');
            const k = kv.shift();
            const v_raw = kv.join('=');

            if (!(k in SettingsManager.ENCODE_FIELDS)) {
                console.error('invalid field for settings', field);
                continue;
            }

            const v = decodeURIComponent(v_raw);
            console.log('v', v);
            settings[k] = SettingsManager.ENCODE_FIELDS[k].parse(v, SettingsManager.DEFAULT[k]);
        }

        return settings;
    }
}
