const axios = require("axios");
const PLAY_AUDIO_BTN_ID = ".audio-captcha-play-button"
const wget = require('node-wget');
const crypto = require('crypto');
const fs = require("fs");
const homedir = require('os').homedir();
const dest_dir = homedir + "/wavs/"
const AUDIO_CAPTCHA_TRACK = ".audio-captcha-track";
const CAPTCHA_CONTAINER = "#captcha-container";
const WAV_URL_REGEX = "https:.+.wav";
const re = new RegExp(WAV_URL_REGEX);
const SPEECH_TO_TEXT_HOST = "http://appointment.lpaconsulting.fr:8000"

// const SPEECH_TO_TEXT_HOST = "http://127.0.0.1:8000"

function delay(delayInMs) {
    return new Promise(resolve => {
        setTimeout(() => {
            resolve(2);
        }, delayInMs);
    });
}

function getRandom() {
    return Math.floor(Math.random() * 3);
}

function getRandomWaitTime() {
    return getRandom() * 1000
}


async function sendRequest(fileName, callback) {
    const fileStream = fs.createReadStream(fileName);
    let response = await axios.post(SPEECH_TO_TEXT_HOST, fileStream, {
        headers: {
            'Content-Type': 'wav',
            'Authorization': 'Bearer 97e36f7e-340e-4c02-b329-9415faee38c3'
        },
        timeout: 90 * 1000
    }).catch(err => {
        console.log(err.code);
        console.log(err.stack);
        console.log(err.message);
        callback([]);
    })
    if (response.status === 200) {
        let result = response.data;
        console.log(result);
        await callback(result);
        console.log("will delete wav file: " + fileName);
        await fs.unlink(fileName, (err) => {
            if (err) throw err;
            console.log(fileName + ' was deleted');
        })
    } else {
        console.log("error");
        await callback([]);
        console.log("will delete wav file: " + fileName);
    }
}

class AudioCaptchaSolver {
    constructor(page, device, isTerminated) {
        this.page = page;
        this.isTerminated = isTerminated
        this.device = device;
    }

    async clearLastDigit(iframeHandler) {
        let selector = "#captcha__audio > div.audio-captcha-input-container > input:nth-child(" + 6 + ")"
        let lastDigit = await iframeHandler.locator(selector).inputValue()
        if (lastDigit !== "") {
            console.log(this.device.model() + ":last digit is not empty, clear it")
            await iframeHandler.locator(selector).fill("")
        } else {
            console.log(this.device.model() + ":last digit is empty, do nothing")
        }
    }

    async solve(onResult) {
        console.log(this.device.model() + ":solve() called.")
        console.log(this.device.model() + ":play audio")
        let iframeHandler = await this.page.frameLocator("body > iframe");
        let playAudioBtn = await iframeHandler.locator(PLAY_AUDIO_BTN_ID);
        try {
            await playAudioBtn.click();
        } catch (e) {
            console.log(e)
        }
        await delay(4000 + getRandomWaitTime());
        let captcha_container = await iframeHandler.locator(CAPTCHA_CONTAINER)
        let html = await captcha_container.innerHTML()
        console.log(this.device.model() + ":audio_tag: " + html);
        if (!html.includes("You have been blocked")) {
            //    find wav from html
            await this.findTextFromWavFile(html, async (number_list) => {
                    console.log("number_list size is " + number_list.length)
                    for (let i = 1; i <= number_list.length; i++) {
                        let selector = "#captcha__audio > div.audio-captcha-input-container > input:nth-child(" + i + ")"
                        // console.log("selector is " + selector)
                        try {
                            await iframeHandler.locator(selector).focus()
                            if (i === 5) {
                                await this.clearLastDigit(iframeHandler)
                            }
                            await iframeHandler.locator(selector).fill("" + number_list[i - 1])
                        } catch (e) {
                            console.log(e)
                        }
                        // fieldInputs[i].value = number_list[i];
                        await delay(500 + getRandomWaitTime());
                    }
                    if (!this.page.isClosed()) {
                        try {

                            let content = await captcha_container.innerHTML()
                            console.log(this.device.model() + ":inner container is " + content)
                            try {
                                if (number_list.length === 0) {
                                    onResult(false)
                                } else {
                                    onResult(true)
                                }
                            } catch (e) {
                                console.log(e)
                            }
                        } catch (e) {
                            console.log(e)
                        }
                    }
                }
            )
        } else {
            await this.device.screenshot({path: crypto.randomUUID() + '.png'});
            await this.resetBrowser()
            onResult(false)
        }
    }

    async findTextFromWavFile(html, callback) {
        let result = re.exec(html);
        //create the directory if not exist
        await fs.promises.mkdir(dest_dir, {recursive: true});
        if (result) {
            let audioUrl = result[0];
            let fileName = crypto.randomUUID() + ".wav";
            wget({url: audioUrl, dest: dest_dir + fileName}, async function (error, response, body) {
                if (error) {
                    console.log('--- error:');
                    console.log(error);            // error encountered
                } else {
                    console.log('download the file successfully');
                    //    send request to get numbers
                    await sendRequest(dest_dir + fileName, callback);
                }
            })
        }
    }

    async resetBrowser() {
        console.log(this.device.model() + ":will reset browser")
        await this.device.shell("pm clear com.android.chrome")
        await delay(1000)
        await this.device.shell("am set-debug-app --persistent com.android.chrome")
        await delay(1000)
        await this.device.shell("pm am start -n com.android.chrome/com.google.android.apps.chrome.Main")
        await delay(1000)
    }

}

module.exports = AudioCaptchaSolver
