
let calculetteMixin = (Base) =>
  class extends Base {
    constructor () {

    }
};

 class Dispatcher {
    constructor () {
        this.events = {};
    };

    addListener (event, callback) {
        // Check if the callback is not a function
        if (typeof callback !== 'function') {
            console.error(`The listener callback must be a function, the given type is ${typeof callback}`);
            return false;
        }
        // Check if the event is not a string
        if (typeof event !== 'string') {
            console.error(`The event name must be a string, the given type is ${typeof event}`);
            return false;
        }

        // Create the event if not exists
        if (this.events[event] === undefined) {
            this.events[event] = {
                listeners: []
            }
        }

        this.events[event].listeners.push(callback);
    };

    removeListener (event, callback) {
        // Check if this event not exists
        if (this.events[event] === undefined) {
            console.error(`This event: ${event} does not exist`);
            return false;
        }

        this.events[event].listeners = this.events[event].listeners.filter(listener => {
            return listener.toString() !== callback.toString();
        });
    };

    dispatch (event, details) {
        // Check if this event not exists
        if (this.events[event] === undefined) {
            console.error(`This event: ${event} does not exist`);
            return false;
        }
        this.events[event].listeners.forEach((listener) => {
            listener(details);
        });
    }
}

// const dispatcher = new Dispatcher();
// Add a listener to "getUserInfo" event
// dispatcher.addListener('getUserInfo', (details) => {
//     console.log(details);
// });
// Calling the API and dispatch the response data
// dispatcher.dispatch('getUserInfo', {
//     username: 'John',
//     accountType: 'admin'
// });


class XpeedyHelpers   {
    helpers= {};
    constructor (){

        this.helpers = {
            async request (url, param = {}) {
                const csrf_token = $('meta[name="csrf-token"]').attr('content');
                let method = ("method" in param) ? param.method : "GET";

                const default_headers = {
                    'X-CSRF-TOKEN': csrf_token,
                    'Content-Type': 'application/json , multipart/form-data',
                    'X-Requested-With': 'XMLHttpRequest',
                };
                let headers = default_headers

                if(("headers" in param)){
                   headers = {...default_headers , ...param.headers}
                }

                if(!("method" in param)){
                    param.method = 'get';
                }

                method = method.toLowerCase();

                if( ("body" in param)){
                    if(method === 'get'){
                        url = url+'?'+ new URLSearchParams(param);
                        delete param.body;
                    }else{ // post
                        param.body = JSON.stringify(param.body);
                    }
                }

                return await fetch(url,param)
                            .catch (error  => {
                                swal.showValidationMessage(`{{__("Error")}} : ${error}`)
                            })
            },

            formatNumber (number,currency = "", separate = " "){
                return number.toString().replace(/\B(?=(\d{3})+(?!\d))/g, separate)+" "+currency;
            },
        }
    }
};


function XpeedyWidget1 (args = {init_url : "" , check_url : ""}){
    return new class extends XpeedyHelpers { }

}

class XpeedyWidget extends XpeedyHelpers {
    theme = "swal";
    lang = "en";
    paymentMethods = [];
    init_url = "";
    check_url = "";
    #selectedMethod;
    #host = "po";
    #footer_powered_by = "<span style='font-size:10px'>Powered by <a href='#'>Xpeedy.com</a></span>";

    #paramsUsedPaymentProcess = {
        init : {} , check : {}
    };

    configs = {
        paymentMethod : null,
        amount : 0,
        currency : "XAF",
        popup_options : { },
        params : {},
        onCompleted : ()=>{ },
        onFailed : ()=>{ },
    };

    constructor (args = {init_url : "" , check_url : ""}){
        super()

        if ('theme' in args) this.theme = args.theme ;
        if ('paymentMethods' in args) this.paymentMethods = args.paymentMethods ;

        if ('init_url' in args) this.init_url = args.init_url ;
        if ('check_url' in args) this.check_url = args.check_url ;

        if ('configs' in args)  this.setConfigs(args.configs);
    };

    setConfigs (configs){
        const C = this.configs;
        this.configs = {...C , ...configs}
    };

    init (){
        try {

            const widget = this;

            const {request, formatNumber} = this.helpers
            const options = this.configs

            const {currency , amount, paymentMethod} = options

            console.log(options);

            this.setSelectedMethod(paymentMethod);

            widget.dataProcess.step_options.init = options;

            //console.log(widget.dataProcess);

            const default_popup_options = {
                title :  "<span> Pay "+formatNumber(amount,currency)+" with "+paymentMethod.name+"</span>",
                imageUrl : paymentMethod.image,
                imageAlt : paymentMethod.name,
                buttonsStyling: true,
                customClass: {
                    input: 'form-control form-control-sm',
                    inputLabel: 'text-left',
                },
                //  inputValue: "23",

                //showDenyButton:true,
                showCancelButton:true,
                showConfirmButton:true,
                cancelButtonColor: "#f27474",
                confirmButtonColor: "#1cc88a",
                cancelButtonText: "Cancel",
                confirmButtonText: "Pay",
                reverseButtons: true,
                showLoaderOnConfirm: true,
                footer : widget.#footer_powered_by,
                allowOutsideClick : false,
                imageWidth: 120,
                imageHeight: 100,
                inputAttributes: { maxlength: 12, },

                allowEnterKey : false,
                inputValidator: (phoneNumber) => {
                    if (!phoneNumber) {
                        return 'The Phone number is required'
                    }
                },
                preConfirm (phoneNumber)  {
                    const  default_data = { phoneNumber, amount, paymentMethodId : paymentMethod.id,};
                    return widget.processPayment({...default_data , ...options.params })
                },
            };

            if(paymentMethod.is_momo){
                default_popup_options.input = 'number';
                default_popup_options.inputLabel = 'Nº '+paymentMethod.name;
                default_popup_options.inputPlaceholder = default_popup_options.inputLabel;
            }
            const swalOptions = { ...default_popup_options, ...options.popup_options};

            swal.fire(swalOptions)

        } catch (error) {
            alert(error)
        }
    }

    dataProcess = {
        checkTransactInterval : null,
        countDownInterval : null,
        payWindow : null,

        clearProcessTimer : () => {
            clearInterval(this.checkTransactInterval);
            clearInterval(this.countDownInterval);
        },

        //Ouvre une nouvelle fenetre (pour les callback paypal)
        openPaypalWindow : (options = {}) => {
            let popupWinWidth = 400;
            let popupWinHeight = 900;
            let  left = (screen.width - popupWinWidth) / 2;
            let  top = (screen.height - popupWinHeight) / 4;
            let url = "";
            let title = "";

            if ('url' in options) url = options.url;
            if ('title' in options) title = options.title;
            if ('left' in options) left = options.left;
            if ('top' in options) top = options.top;
            if ('popupWinHeight' in options) popupWinHeight = options.popupWinHeight;
            if ('popupWinWidth' in options) popupWinWidth = options.popupWinWidth;

            this.payWindow = window.open(
                                    url,
                                    title,
                                    "left="+left+",top="+top+",width="+popupWinWidth+",height="+popupWinHeight+",toolbar=0,scrollbars=0,status=0,resizable=no"
                                );

            // this.payPalWindow.document.write(
            //     "<script>window.opener.document.body.innerHTML = 'Test'<\/script>"
            // );

        },

        //Backup  des options utilisées dans chaque étapes
        step_options : {
            init : {},
            check : {},
        }
    };

    #checkTransactInterval = null;
    #countDownInterval = null;
    #payPalWindow = null;

    #getpayPalWindow (arg= {}){
        return
    };

    #clearProcessTimer(){
        clearInterval(this.dataProcess.checkTransactInterval);
        clearInterval(this.dataProcess.countDownInterval);
    }

    setSelectedMethod (paymentMethod){
        this.#selectedMethod = paymentMethod;
    }
    paymentCountDown (time) {
        let $countDowMinute = document.getElementById("countdown-minute");
        let $countDowSecond = document.getElementById("countdown-second");
        let $timeOutMessage = document.getElementById("timeout-message");
        let currentMin = parseInt($countDowMinute.textContent);
        let currentSec = parseInt($countDowSecond.textContent);

        console.log("min = "+currentMin,"sec = "+currentSec);
        //debut du chrono
        if (currentSec === 0 && currentMin === 0){
            $countDowMinute.innerText = '00';
            $countDowSecond.innerText = "01";
            return ;
        }

        if(currentSec === 60 ){  // si atteint 60s
            if(currentMin <= 8){
                $countDowMinute.innerText = "0"+(currentMin + 1);  // on ajoute 1 min
            }else{
                $countDowMinute.innerText = currentMin + 1; // on ajoute 1 min
            }
            $countDowSecond.innerText = '00'; // reset les sec à 00
        }
        else{
            /*puisqu'on veut formater l'affichage(00-09) , on teste si la sec actuelle est <= 8
             à cause du comportement de la fonction setIntervalle() qui lui fonctionne sur le
              principe d'un do-while qui en faite s'execute au moins une fois avant de tester une condition
              logiquement sa devrait etre <= 9 , mais avec ceci , quand le chrono
              arrivera à 09 au lieu de passer directement à 10 il affichera 010*/

            let $countDowSecondText = (currentSec <= 8 )
                                      ? '0'+(currentSec + 1)
                                      : currentSec + 1;
            $countDowSecond.innerText = $countDowSecondText; //on ajoute 1s
        }

        //a la fin du chrono
        if (currentSec === 0 && currentMin === time){
            let $countDowMinuteText = (time >= 10 ) ? time : "0"+time;
            $countDowMinute.innerText = $countDowMinuteText;
            $countDowSecond.innerText = '00';
            $timeOutMessage.style.display = "block";
        }
    };

    handlePaymentCompleted (){

    }

    async startToCheckTransaction ( args  = {data : {} ,time_check_status : 0, timeout : 0}){
        const widget = this;
        const {request, formatNumber} = widget.helpers;

        const payPalWindow = widget.#payPalWindow();

        const {time_check_status , data} = args;

        const {reference} = data.transaction;

         /*check le statut de la transaction toute les 2min*/
         widget.dataProcess.checkTransactInterval = setInterval( async () => {

           const body = { "reference" : reference,};

           const response =  await request(widget.check_url+"/"+reference,{ body ,method : "post"});

           const status   =   await response.status ;

           const data     =   await response.json();

           if (status === 500){
                alert(data.message)
           }

           let transaction = data.transaction;
            let payment = data.payment;
            let config = {
                title : transaction.message,
                icon : "success",
                position: (payment.saved) ? 'top-end':'bottom-end',
                timer: 5000,
                // ok_button: true,
            };
            if(transaction.success){
                try {
                    if(typeof payPalWindow !== "undefined" && payPalWindow ){
                        payPalWindow.close();
                    }
                }catch (e) {
                    console.log(e)
                }finally {
                    // si on arrete de check le statut
                    if(transaction.stop_check_status){
                        widget.#clearProcessTimer();
                        // si le payment a été enregistré dans la bd
                        if (payment.saved){
                            toast(config);
                            widget.handlePaymentCompleted()
                        }else{
                            swal.showValidationMessage(`${payment.message}`);
                        }
                    }
                }

            }
            else if(transaction.failed){
                widget.#clearProcessTimer();
                swal.showValidationMessage(`${transaction.message}`)
            }
            else if(transaction.pending){}

        },
        time_check_status
        );

        /*décompteur*/
        this.#countDownInterval = setInterval(() => { widget.paymentCountDown(timeout); }, 1000);

    }

   async processPayment(body = {},orther = {swalOptions : {}}){

        const widget = this;
        const {request, formatNumber} = widget.helpers;

        const init_options = this.dataProcess.step_options.init;

        const popup_options = init_options.popup_options;

        const response =  await request(init_url,{ body , method : "post" });
        let status     = await response.status;
        const data     = await response.json();

        if ('success' in data){
            const success = data.success ;

            if(success){
                console.log("transaction init successfully" );

                if('callback_url' in data){ // PayPal-Rest
                   return widget.dataProcess.openPaypalWindow({url : response.callback_url});
                }
                if( ('transaction' in data)){
                    let transaction = data.transaction;
                    console.log(transaction);

                    if(transaction){
                        let minute = 60 * 1000; // 1min
                        let reference = transaction.reference; // ref de la transaction
                        const timeout = transaction.timeout;  // en min

                        widget.dataProcess.countdown.time_check_status = transaction.time_check_status ; // en s
                        widget.dataProcess.countdown.timeout = timeout ;

                        swal.fire({
                            title: popup_options.title,
                            html:  transaction.waiting_alert, // l'alerte d'attente retourné
                            imageUrl: popup_options.imageUrl,
                            imageWidth: popup_options.imageWidth,
                            imageHeight: popup_options.imageHeight,
                            imageAlt: popup_options.imageAlt,

                            showConfirmButton : false,
                            showCancelButton : false,
                            reverseButtons : true,
                            allowOutsideClick : false,

                            timer : timeout * minute, // en (s) le nbre de secondes qui sera programmmé sur le timer de swal (barre de progression)
                            timerProgressBar: true, // afficher la progressBar

                            didOpen : () => {
                                widget.startToCheckTransaction(data)
                            },
                            willClose : () => {
                                widget.dataProcess.clearProcessTimer();
                            },
                        })
                    }
                }
            }else{
                swal.showValidationMessage(`${data.message}`);
                console.log("transaction init failed" );
            }

        }
    };

    checkPayment(){

    };

   async initPayment(param = { popup_options : {}}){
        try {

            const default_options = {
                paymentMethod : null,
                amount : 0,
                params : {},
                currency : "XAF",
                onCompleted (response){

                },
                onFailed (response){

                },
                onInit (response){

                },
            };

            const {request, formatNumber} = this.helpers
            const options = {...default_options , ...param}

            const {currency , amount, paymentMethod} = options

            const widget = this;

            //options.title =  "<span> Pay "+formatNumber(amount,currency)+" with "+paymentMethod.name+"</span>";

            console.log(options);

            this.setSelectedMethod(paymentMethod);

            console.log(widget.paramsUsedPaymentProcess);

            widget.dataProcess.step_options.init = options;

            const default_popup_options = {
                title :  "<span> Pay "+formatNumber(amount,currency)+" with "+paymentMethod.name+"</span>",
                imageUrl : paymentMethod.image,
                imageAlt : paymentMethod.name,
                buttonsStyling: true,
                customClass: {
                    input: 'form-control form-control-sm',
                    inputLabel: 'text-left',
                },
                // inputValue: 233,

                //showDenyButton:true,
                showCancelButton:true,
                showConfirmButton:true,
                cancelButtonColor: "#f27474",
                confirmButtonColor: "#1cc88a",
                cancelButtonText: "Cancel",
                confirmButtonText: "Pay",
                reverseButtons: true,
                showLoaderOnConfirm: true,
                allowOutsideClick : false,
                imageWidth: 120,
                imageHeight: 100,
                inputAttributes: {
                    'id': "text-phone-number",
                        maxlength: 12,
                    // autocapitalize: 'off',
                    //    autocorrect: 'off',
                },

                allowEnterKey : false,
                inputValidator: (value) => {
                    if (!value) {
                        return 'The Phone number is required'
                    }
                },

                preConfirm (value)  {

                    const  default_data = {
                        phoneNumber : value,
                        amount,
                        paymentMethodId : paymentMethod.id,
                    };

                    return widget.processPayment({...default_data , ...options.params })
                },
            };

            if($.inArray(paymentMethod.code,["orange-momo-cmr","mtn-momo-cmr"]) !== -1){
                default_popup_options.input = 'number';
                default_popup_options.inputLabel = 'Nº '+paymentMethod.name;
                default_popup_options.inputPlaceholder = default_popup_options.inputLabel;
            }
            const swalOptions = { ...default_popup_options, ...param.popup_options};

            swal.fire(swalOptions)

        } catch (error) {


            alert(error)
        }

    }
}





