import log4js from 'log4js'
import qs from 'qs'
import {genPayload2, genPayload4} from "./step2.js"
import {genPc, genUuid} from "./utils.js"
import axios from "axios";
import {encodePayload} from './encodepayload.js'

const ie = (t, e) => {
    for (var n = '', r = 0; r < t.length; r++)
        // console.log(e, t.charCodeAt(r), e ^ t.charCodeAt(r), String.fromCharCode(e ^ t.charCodeAt(r)))
        n += String.fromCharCode(e ^ t.charCodeAt(r))

    return n
}

function randint(a, b) {
    return Math.floor(Math.random() * (b - a + 1) + a);
}


log4js.configure({
    appenders: {
        out: {
            type: 'stdout', layout: {
                colored: true,
                type: 'pattern',
                pattern: '%[%d{yyyy-MM-dd hh:mm:ss.SSS}] [%l:%C:%M] [%p] %c - %m',
            }
        },
    },
    categories: {
        default: {appenders: ['out'], level: "trace", enableCallStack: true}
    }

});

class PxBypass {
    tag = "v8.7.2"
    ft = "317"
    appId = "PXVb73hTEg"
    ua = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36'
    pxHeaders = {
        "authority": "collector-pxvb73hteg.px-cloud.net",
        "accept": "*/*",
        "accept-language": "en-US,en;q=0.9",
        "cache-control": "no-cache",
        "content-type": "application/x-www-form-urlencoded",
        "origin": "https://www.flyfrontier.com",
        "pragma": "no-cache",
        "user-agent": this.ua
    }
    pxUrl = `https://collector-${this.appId}.px-cloud.net/api/v2/collector`
    tlsUrl = 'http://52.52.23.116/tls/forward'

    prox = `http://user-uni001-region-us-sessid-${randint(1000, 5000)}-sesstime-5-keep-true:q39CEBTs5A5YQXor@pr.roxlabs.cn:4600`
    // prox = `http://unfflcc:76cc14-47b8dd-1f8ace-827836-0c740e@usa.rotating.proxyrack.net:${randint(10000, 13500)}`
    // prox = 'http://127.0.0.1:8890'
    // tlsUrl = 'http://127.0.0.1:58000/tls/forward'

    constructor(options) {

        this.log = log4js.getLogger('px')

        this.url = 'https://www.flyfrontier.com/'
        this.log.level = 'debug'
        this.uuid = '';
        this.ts = '';
        this.cs = ''
        // # PX15454 o111oooo
        this.num1 = 0
        // # PX11701 111o1o
        this.num2 = ''
        // # PX11701 111o1o
        this.str1 = ''
        this.vid = ''
        this.sid = ''
        this.cts = ''

        this.seq = 0
        this.rsc = 1;
        this.cookies = {}


    }

    async sleep(ms) {
        return new Promise(resolve => setTimeout(resolve, ms));
    }

    async add_headers() {
        let cks = Object.keys(this.cookies).map((v, k) => `${v}=${this.cookies[v]}`).join('; ')

        let headers = {
            "authority": "booking.flyfrontier.com",
            "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
            "accept-language": "en-US,en;q=0.9",
            "user-agent": this.ua,
            "cookie": cks
        }
        let res = await axios.post('http://ymx-lcc.unififi.com/header/add', JSON.stringify({
            'brush_fromto': 'LAS-BOS',
            'brush_fromdate': '2023-05-26',
            'brush_header': headers,
            'brush_proxy': this.prox,
            'brush_mode': 'shopping',
            'brush_name': 'js0',
            'brush_type': 'cookieF9',
        }));
        this.log.debug(res.data)

    }

    async do_collector(data) {
        try {
            if (typeof data === 'object') {
                data = JSON.stringify(data)
            }
            let payload = encodePayload(data, this.uuid, this.ts)
            let pc = genPc(data, `${this.uuid}:${this.tag}:${this.ft}`)
            let body = {
                "appId": this.appId,
                "tag": this.tag,
                "uuid": this.uuid,
                "ft": this.ft,
                "seq": this.seq,
                "en": "NTA",
                "pc": pc,
                "rsc": this.rsc,
                "payload": payload,
            }
            body = this.updateBody(body);

            // this.log.info(body)

            let res = await axios.post(this.tlsUrl, JSON.stringify({
                url: this.pxUrl,
                data: qs.stringify(body),
                headers: this.pxHeaders,
                allow_redirects: true,
                debug: true,
                proxy: this.prox,
            }));
            let inRes = JSON.parse(res.data.text)
            // this.log.info(inRes)
            this.parseRes(inRes)
        } catch (err) {
            console.error(err);
        }

        this.seq++;
        this.rsc++;

    };


    updateBody(body) {
        if (this.vid !== "") {
            body.vid = this.vid
        }
        if (this.cs !== "") {
            body.cs = this.cs
        }
        if (this.cts !== "") {
            body.cts = this.cts
        }
        if (this.sid !== "") {
            body.sid = this.sid
        }
        return body
    }

    parseRes(inRes) {
        if (inRes['ob']) {
            let cks = ie(atob(inRes.ob), this.version()).split('~~~~')
            this.log.info(cks.length, JSON.stringify(cks, null, '\t'))
            for (var ck of cks) {
                let tmp = ck.split('|');
                if (tmp[0] === 'o111ooo1') {
                    this.ts = tmp[1]

                }
                if (tmp[0] === 'o111oooo') {
                    this.num1 = parseInt(tmp[1])

                }
                if (tmp[0] === '111o1o') {
                    this.num2 = tmp[1]
                }

                if (tmp[0] === '1oooo1') {
                    this.str1 = tmp[1]

                }
                if (tmp[0] === 'o1oo1o') {
                    this.vid = tmp[1]
                    this.cookies['_pxvid'] = this.vid
                }


                if (tmp[0] === 'o11o11') {
                    this.sid = tmp[1]
                }

                if (tmp[0] === '11o111') {
                    this.cs = tmp[1]
                }

                if (tmp[0] === 'o11o11oo') {
                    this.cts = tmp[1]
                    this.cookies['pxcts'] = this.cts
                }

                if (tmp.includes('pxde')) {
                    this.cookies['pxde'] = tmp[3]
                }
                if (tmp.includes('_px2')) {
                    this.cookies['_px2'] = tmp[3]
                    this.log.debug(`px2_decode ${atob(this.cookies['_px2'])}`)

                }

            }
        }
    }

    version() {
        return parseInt(this.tag.substring(1).replaceAll('.', '')) % 128
    }

    async step1() {
        this.log.info(`proxy ${this.prox}`)

        // this.log.info('setp1')
        let t1 = new Date().getTime();
        this.startTs = t1
        let t2 = t1 + randint(5, 30)
        this.startTs2 = t2
        this.performanceNow = randint(3000, 5000)
        this.px12280 = this.startTs2 + this.performanceNow

        this.uuid = genUuid()
        let data = [{
            "t": "PX12095",
            "d": {
                "PX11645": this.url, "PX12207": 0, "PX12458": "MacIntel", "PX11902": 0,
                "PX11560": randint(24846, 24846 * 2), "PX12248": 3600, "PX11385": t1, "PX12280": t2,
                "PX11496": this.uuid, "PX12564": null, "PX12565": -1,
                "PX11379": true
            }
        }]
        let res = await this.do_collector(data)
        this.seq++;

    }

    async step2() {
        this.performanceNow += randint(1000, 2000)

        let data = [{"t": "PX12167", "d": {"PX11648": true}}]
        let res = await this.do_collector(data)

    }

    async step3() {
        this.performanceNow += randint(1000, 2000)
        let data = genPayload2(this.url, this.sid, this.vid, this.ts, this.num1, this.num2,
            this.str1, this.uuid,
            this.startTs, this.startTs2, this.performanceNow, this.px12280)
        let res = await this.do_collector(data)

    }

    async step4() {
        this.performanceNow += randint(1000, 2000)
        let data = genPayload4(this.url, this.sid, this.vid, this.ts, this.num1, this.num2,
            this.str1, this.uuid,
            this.startTs, this.startTs2, this.performanceNow, this.px12280)
        let res = await this.do_collector(data)
    }

    async test() {
        // this.prox = 'http://127.0.0.1:8890'
        // this.tlsUrl = 'http://127.0.0.1:58000/tls/forwardios'

        let cks = Object.keys(this.cookies).map((v, k) => `${v}=${this.cookies[v]}`).join('; ')
        let res = await axios.post(this.tlsUrl, JSON.stringify({
            url: 'https://booking.flyfrontier.com/Flight/InternalSelect?o1=DEN&d1=LAS&dd1=2023-12-30&ADT=1&umnr=false&mon=true',
            headers: {
                "authority": "booking.flyfrontier.com",
                "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
                "accept-language": "en-US,en;q=0.9",
                "cache-control": "no-cache",
                "pragma": "no-cache",
                "sec-ch-ua": "\"Google Chrome\";v=\"117\", \"Not;A=Brand\";v=\"8\", \"Chromium\";v=\"117\"",
                "sec-ch-ua-mobile": "?0",
                "sec-ch-ua-platform": "\"macOS\"",
                "sec-fetch-dest": "document",
                "sec-fetch-mode": "navigate",
                "sec-fetch-site": "none",
                "sec-fetch-user": "?1",
                "upgrade-insecure-requests": "1",
                "user-agent": this.ua,
                "cookie": cks
            },
            allow_redirects: true,
            debug: true,
            method: "GET",
            proxy: this.prox,

        }));

        if (res.data.status_code === 200) {
            this.log.warn('success', res.data.status_code, res.data.text.includes('FlightData'))
            await this.add_headers()
        } else {
            this.log.error('error', res.data.status_code)
        }
    }
}

async function run() {
    let px = new PxBypass()
    await px.step1()
    await px.step2()
    await px.sleep(1500)
    await px.step3()
    await px.step4()
    await px.sleep(1500)

    await px.test()
}


run()
