/**
 * новая весия v0.2.00
 * Все тексты ошибок Didox перенести в конф
 * сейчас показывается текст response (местами)
 * 
 * ошибка loadKeysErrorCbf в контексте вызова this
 * loadKeysErrorCbf нужно написать тексты ошибок 
 * 
 * добавить функция для документов уже созданных в черновиках 
 * если документ уже подписан в didox 
 * 
 * и функцию проверки которая будет проверять статус и состояние документа 
 * подписан или нет удален или нет 
 * 
 */

(function (){
    window.CDocSign = getDocSign();

    function getDocSign () {
        function DocsSign () {
            this.userSNumber = '';
            this.vo = {};
            this.keyId = '';

            this.DIDOX = {
                noEDP: false,
                token: '',
                authId: '',
                signature: ''
            }

            this.EIMZO = {
                keyId: ''
            }
        
            // is current E-IMZO verison
            this._isCVersion = false;

            this.errorCAPIWS = 'Ошибка соединения с E-IMZO. Возможно у вас не установлен модуль E-IMZO или Браузер E-IMZO.';
            this.errorBrowserWS = 'Браузер не поддерживает технологию WebSocket. Установите последнюю версию браузера.';
            this.errorUpdateApp = 'ВНИМАНИЕ !!! Установите новую версию приложения E-IMZO или Браузера E-IMZO.<br /><a href="https://e-imzo.uz/main/downloads/" role="button">Скачать ПО E-IMZO</a>';
            this.errorWrongPassword = 'Пароль неверный.';
            this.errorTaxId = 'У сделки нет обязательного поля (ИНН).';
            this.errorPDF = 'Не найден pdf файл.';
            this.errorTaxIdInfalid = 'У сделки нет обязательного поля (ИНН).';
            this.errorEDPEmpty = 'Для продолжения нужен ЭЦП';
            this.errorSignDoc = 'Не удалось подписать документ';

            // token working time in hours
            this.TOKEM_LIMOT = this._currentLimit(24 - 1);
            // pkcs7 working time in hours 
            // this.DAUTH_ID_LIMIT = 6 - 1;
            this.DAUTH_ID_LIMIT = this._currentLimit(6 - 1);
            // plcs7 signature time limit in hours
            this.SIGNATURE_LIMIT = this._currentLimit(6 - 1);

            // didox auth id storage key 
            this.SAUTH_KEY = '__d.authid';
            // didox token storage key
            this.SDTOKEN_KEY = '__d.token';
            //
            this.SSIGNATURE_KEY = '__d.signature';
            // saved data on auth with TIN
            this.SFORM_TIN = '__d.form_tim';

            // api keys
            this.EIMZO_API_KEYS = [
                'localhost', '96D0C1491615C82B9A54D9989779DF825B690748224C2B04F500F370D51827CE2644D8D4A82C18184D73AB8530BB8ED537269603F61DB0D03D2104ABF789970B',
                '127.0.0.1', 'A7BCFA5D490B351BE0754130DF03A068F855DB4333D43921125B9CF2670EF6A40370C646B90401955E1F7BC9CDBF59CE0B2C5467D820BE189C845D0B79CFC96F',
                'null', 'E0A205EC4E7B78BBB56AFF83A733A1BB9FD39D562E67978CC5E7D73B0951DB1954595A20672A63332535E13CC6EC1E1FC8857BB09E0855D7E76E411B6FA16E9D',
                'dls.yt.uz', 'EDC1D4AB5B02066FB3FEB9382DE6A7F8CBD095E46474B07568BC44C8DAE27B3893E75B79280EA82A38AD42D10EA0D600E6CE7E89D1629221E4363E2D78650516'
            ];

            // this.buyerInfo = {
            //     address: ['bx', 'didox'],
            //     name: ['bx', 'didox'],
            //     tin: ['bx', 'didox'],
            // };
            // this.CASHE = {
            //  key: {limit: ''}
            // }

            // 
            this.checkVersion();
        }
        
        DocsSign.prototype = {

            /**
             * main
             * @param {Function} success 
             * @param {Function} error
             */
            sign: function (success) {
                var self = this;

                if (!success) {
                    success = function () {}
                }

                success.bind(self);

                if (this.isCurrentVersion()) {
                    callAuth();
                } else {
                    self._uiShowMessage(self.errorCAPIWS);
                    callAuth();
                }

                function callAuth () {
                    EAuth.call(self.isCurrentVersion(), function (data) {
                        var params = {};
                        var vo = data.vo;
                        var auth = data.auth;
                        var onTokenLoaded = data.onTokenLoaded;
    
                        // if (!auth.token) {
                            self.ckeckTokens(vo, auth, function (token) {
                                Didox.setUserKey(token);
                                self._callFunc(onTokenLoaded, vo, auth, token);

                                success(vo, auth, token);
                            });
                        // } else {
                        // }
                    });
                } 
            },

            createDoc: function (doc, success) {
                var self = this,
                    pdfUrl = App.getDocPdfUrl(doc),
                    taxId = this.getDealTIN(),
                    buyer = this.getBuyer();

                if (!taxId) {
                    this._uiShowMessage(this.errorTaxId);
                    return;
                }

                if (!pdfUrl) {
                    this._uiShowMessage(this.errorPDF);
                    return;
                }

                this.sign(function (vo, auth, token) {
                    App.loadFile(pdfUrl, function (pdfB64) {
                        var tin = '';
                        if (vo) {
                            tin = vo.TIN;
                        } else {
                            tin = auth.tin;
                        }

                        getTinInfo(tin, function (selerFI) {
                            getTinInfo(taxId, function (bayerFI) {
                                buyer = self.extendsBuyer(buyer, bayerFI);
                                crateDocument(
                                    self.createDocNode(doc, {
                                        buyer: buyer,
                                        seller: {
                                            name: selerFI.fullName,
                                            address: selerFI.address,
                                            tin: selerFI.tin,
                                        },
                                        document: pdfB64
                                    })
                                );
                            });
                        });
                    });
                });
                

                function crateDocument (data) {
                    self.createDidoxDoc('000', data, 
                        function (data) {
                            // success
                            self._callFunc(success, data);

                        }, function (data) {
                            // error
                            if (typeof data.responseText === 'string') {
                                self._uiShowMessage(data.responseText);
                            } else {
                                self._uiShowMessage(data.error.message);
                            }                            
                        }, function (data) {
                            // fail
                            self._uiShowMessage(data.data.error.message);
                        }
                    );
                }

                function getTinInfo(tin, success) {
                    self.loadFullInfoByTin(tin, function (data) {
                        // success
                        success(data);
                    }, function (data) {
                        // error
                        var msg = data.responseJSON.message;
                        if (!msg) {
                            msg = self.errorTaxIdInfalid;
                        }
                        self._uiShowMessage(msg);
                    }, function (data) {
                        // fail
                        self._uiShowMessage(data.responseJSON.message);
                    });
                }
            },
            signDoc: function (docId, success, error) {
                var self = this;

                this.sign(function (vo, auth, token) {
                    if (!vo) {
                        self._callFunc(error, self.errorEDPEmpt);
                        return;
                    }

                    Didox.getDoc(docId, function (docData) {
                        self.laodEImzoKey(vo, function (id) {

                            EIMZOClient.createPkcs7(id, self._getSignatureString(docData), function (hexId, func) {
                                Didox.getTimestamp({
                                    signatureHex: hexId
                                }, function (res) {
                                    func(res.timeStampTokenB64);
                                });
                            }, function (pkcs7) {
                                self.signDidoxDoc(docId, {
                                    signature: pkcs7
                                }, function (data) {
                                    self._callFunc(success, data);

                                    App.eventRegist('doc_sign', {
                                        domain: App.getDomain(),
                                        date: moment().format(App.uiGetFullDate())
                                    });
                                }, function (data) {
                                    if (data.message) {
                                        self._uiShowMessage(data.message);
                                    } else {
                                        self._uiShowMessage(self.errorSignDoc);
                                    }
                                    self._callFunc(error, data);
                                }, function (data) {
                                    self._callFunc(error, data);
                                });
                            }, self.loadKeysErrorCbf);

                        }, self.loadKeysErrorCbf);
                    }, function (data) {
                        self._callFunc(error, data);
                    }, function (data) {
                        self._callFunc(error, data);
                    });

                });

                return;
                
            },



            deleteDoc: function (docId, success, error) {
                var self = this;

                this.sign(function (vo, auth) {
                    if (!vo) {
                        self._callFunc(error, self.errorEDPEmpty);
                        return;
                    }
                    
                    Didox.docTosign(docId, {
                        action: "cancel"
                    }, function (res) {
                        self.laodEImzoKey(vo, function (id) {
                            EIMZOClient.createPkcs7(id, JSON.stringify(res), function (hexId, func) {
                                Didox.getTimestamp({
                                    signatureHex: hexId
                                }, function (res) {
                                    func(res.timeStampTokenB64);
                                });
                            }, function (pkcs7) {
                                Didox.delateDoc(docId, {
                                    signature: pkcs7
                                },function (res) {
                                    self._callFunc(success, res);
                                }, callError, callError);
                            }, self.loadKeysErrorCbf);
                        }, self.loadKeysErrorCbf);

                    }, callError, callError);

                });

                function callError (er) {
                    self._callFunc(error, er);
                }
            },
            deleteDraftDoc: function (docId, success, error) {
                var self = this;

                this.sign(function (vo, auth) {
                    Didox.deleteDocInDraf(docId, function (res) {
                        self._callFunc(success, res);
                    }, function () {
                        self._callFunc(error, res);
                    }, function (res) {
                        self._callFunc(error, res);
                    });
                });
            },



            /**
             * checking basic saved data (pkcs7, didoxToken)
             * @public ckeckTokens
             * @param {Object} vo 
             * @param {Function} success - args vo, token
             * @param {Function} error 
             * @returns 
             */
            ckeckTokens: function (vo, auth, success, error) {
                var self = this, sAuthId, sDToken, sSignature;
                
                if (!vo && auth) {
                    var sTin = self.getSData(self.SFORM_TIN);
                    sDToken = self.getSData(self.SDTOKEN_KEY);

                    if (App.checkSavedData(sDToken, self.getSTokenLimot())) {
                        self.DIDOX.token = sDToken.data;
                        self._callFunc(success, sDToken.data, null);
                    } else {
                        Didox.loadTokenByTin(auth.tin, {
                            password: auth.password
                        }, function (token) {
                            self.saveSData(self.SDTOKEN_KEY, null, token);
                            
                            if (auth.tin) {
                                self.saveSData(self.SFORM_TIN, null, auth.tin);
                            } else {
                                self.saveSData(self.SFORM_TIN, null, sTin.data);
                            }

                            self._callFunc(success, token, null);
                        }, function (data) {
                            console.error(data);
                            self._uiShowMessage('Произошла неизвестная ошибка');
                        }, function (data) {
                            console.error(data);
                            self._uiShowMessage('Произошла неизвестная ошибка');
                        });
                    }
                } else if (vo && !auth) {
                    sDToken = self.getSData(self.SDTOKEN_KEY, vo);
                    sAuthId = self.getSData(self.SAUTH_KEY, vo);
                    sSignature = self.getSData(self.SSIGNATURE_KEY, vo);

                    if (App.checkSavedData(sDToken, self.getSTokenLimot())) {
                        if (App.checkSavedData(sAuthId, self.getSDAuthIdLimot())) {
                            self.DIDOX.token = sDToken.data;
                            self.DIDOX.authId = sAuthId.data;
                            self._callFunc(success, sDToken.data, vo);
                        } else {
                            self._loadAuthId(vo, function (pkcs7, authId, id) {
                                self.DIDOX.authId = authId;
                                self.saveSData(self.SAUTH_KEY, vo, authId);
    
                                self._callFunc(success, sDToken.data, vo);
                            }, pkcs7Fail)
                        }
                    } else {
                        self._loadAuthId(vo, function (pkcs7, authId, id) {
                            self.DIDOX.authId = authId;
                            self.saveSData(self.SAUTH_KEY, vo, authId);
                                
                            self.loadDidoxToken({
                                pkcs7: pkcs7,
                                serialNumber: vo.serialNumber
                            }, function (data) {
                                // success
                                self.DIDOX.token = data.token;
                                self.saveSData(self.SDTOKEN_KEY, vo, data.token);
        
                                self._callFunc(success, data.token, vo);
                            }, function (data) {
                                // error
                                if (typeof data.responseText === 'string') {
                                    self._uiShowMessage(data.responseText);
                                } else {
                                    self._uiShowMessage(data.error.message);
                                }
                            }, function (data) {
                                // fail 
                                if (typeof data.responseText === 'string') {
                                    self._uiShowMessage(data.responseText);
                                } else {
                                    self._uiShowMessage(data.error.message);
                                }
                                
                            });
                        }, pkcs7Fail);
                    }
                }

                function pkcs7Fail (e, r) {
                    self.loadKeysErrorCbf(e, r);
                    self._callFunc(error, e, r);
                }
            },
            ckeckSignature: function (vo, success, error) {
                var self = this;

                if (!vo) {
                    return ;
                }

                self.laodEImzoKey(vo, function (id) {
                    self.createPkcs7(id, vo.TIN, function (pkcs7) {
                        self.DIDOX.signature = pkcs7;
                        self._callFunc(success, pkcs7, vo);
                    }, self.loadKeysErrorCbf, self.loadKeysErrorCbf);
                }, self.loadKeysErrorCbf);
            },
        
            checkVersion: function () {
                var self = this;
                EIMZOClient.checkVersion(success, error);
        
                function success (major, minor) {
                    var newVersion = self.EIMZO_MAJOR * 100 + self.EIMZO_MINOR;
                    var installedVersion = parseInt(major) * 100 + parseInt(minor);
                    if (installedVersion < newVersion) {
                        self._isCVersion = false;
                        self._uiAppdateApp();
                    } else {
                        self._isCVersion = true;
                    }
                }
        
                function error (e, r) {
                    if (r) {
                        self.__callFunc(self.events.onShowMessage, r);
                    } else {
                        self.__callFunc(self.events.onNotLoaded, e);
                    }
                }
            },

            loadAuthId: function (vo, success, error, fail) {
                Didox.loadAuthId(vo.serialNumber, success, error, fail);
            },
            laodEImzoKey: function (vo, success, error) {
                var self = this;

                EIMZOClient.loadKey(vo, function (id) {
                    self.keyId = id;
                    success(id);
                }, error);
            },
            loadDidoxToken: function (node, success, error, fail) {
                Didox.loadToken(node, success, error, fail)
            },
            loadFullInfoByTin: function (tin, success, error, fail) {
                Didox.getInfoByTaxId(tin, success, error, fail);
            },
            createDidoxDoc: function (docType, node, success, error, fail) {
                Didox.createDoc(docType, node, success, error, fail);
            },
            signDidoxDoc: function (docId, node, success, error, fail) {
                Didox.signDoc(docId, node, success, error, fail);
            },

            createPkcs7: function (id, data, success, fail) {
                EIMZOClient.createPkcs7(id, data, null, success, fail);
            },

            /**
             * checks if the token has expired
             * @public checkToken
             * @param {Number} limit - teken's active time in seconds
             * @param {Date|Number} now - The current date
             * @param {Number} saved - the date of the saved token
             * @returns {Boolean}
             */
            checkToken: function (limit, now, saved) {
                var res = now - saved;

                if (limit <= res) {
                    return false;
                }
                return true;
            },


            getSData: function (key, vo) {
                var result;

                if (!vo) {
                    result = AppStorage.get(key);
                } else {
                    result = AppStorage.get(key + '_' + vo.serialNumber);
                }
                if (result.data) {
                    return result;
                }
                return {};
            },
            saveSData: function (key, vo, data) {
                if (!vo) {
                    AppStorage.set(key, data);
                } else {
                    AppStorage.set(key + '_' + vo.serialNumber, data);
                }
            },

            /**
             * 
             * @returns {String}
             */
            getDealTIN: function () {
                return App.getDealTIN();
            },
            getBuyer: function () {
                if (typeof deal !== 'object') {
                    return null;
                }

                return {
                    address: '',
                    name: '',
                    tin: '',
                }
            },
            extendsBuyer: function (buyer, fullInfo) {
                var res = {};

                extenObj({
                    name: 'shortName',
                    address: 'address',
                    tin: 'tin',
                });

                return res;

                function extenObj (params) {
                    Object.keys(params).forEach(function (key) {
                        var FIKey = params[key];
                        if (!buyer[key]) {
                            res[key] = fullInfo[FIKey];
                        } else {
                            res[key] = buyer[key];
                        }
                    });
                }
            },
            createDocNode: function (doc, params) {
                var node = {

                };
                
                node.data = {
                    Buyer: {
                        DepartmentName: '',
                        DepartmentTin: '',
                        Name: params.buyer.name,
                        Address: params.buyer.address,
                    },
                    BuyerTin: params.buyer.tin,
                    Document: {
                        DocumentNo: doc.number,
                        DocumentDate: this._getDocDate(doc),
                        DocumentName: doc.title,
                    },
                    ContractDoc: {
                        ContractNo: doc.number,
                        ContractDate: this._getDocContractDate()
                    },
                    SellerTin: params.seller.tin,
                    Seller: {
                        Name: params.seller.name,
                        Address: params.seller.address
                    },
                    didoxorderid: ''
                };

                if (params.document) {
                    node.document = params.document;
                }

                return node;
            },
            _getDocDate: function (doc) {
                var date = doc.createTime;
                var result = '';

                if (date && false) {
                    result = moment(date).format(App.didoxDateFormat());
                } else {
                    result = moment().format(App.didoxDateFormat());
                }

                return result;
            },
            _getDocContractDate: function () {
                return moment().format(App.didoxDateFormat());;
            },
            _getSignatureString: function (doc) {
                return JSON.stringify(doc.data.json);
            },


            /**
             * Get Saved Token Limit time
             * @public 
             * @param {Number} num - 
             * @returns {Number} - token active time in seconds
             */
            getSTokenLimot: function () {
                return this.TOKEM_LIMOT
            },
            /**
             * Get Saved Didox Auth Id Limit time
             * @public
             * @param {Number} num 
             * @returns {Number}
             */
            getSDAuthIdLimot: function () {
                return this.DAUTH_ID_LIMIT
            },
            /**
             * Get Saved Signature Limit time 
             * @public
             * @param {Number} num 
             * @returns {Number}
             */
            getSSignatureLimot: function () {
                return this.SIGNATURE_LIMIT
            },
            _currentLimit: function (h) {
                return h * 60 * 60 * 1000;
            },


            loadKeysErrorCbf: function (e, r) {
                var self = this;

                if (r) {
                    if (r.indexOf("BadPaddingException") != -1) {
                        self._uiShowMessage(self.errorWrongPassword);
                    } else {
                        self._uiShowMessage(r);
                    }
                } else {
                    self._uiShowMessage(self.errorBrowserWS);
                } if (e) {
                    self._wsError(e);
                }
            },

            isCurrentVersion: function () {
                return this._isCVersion;
            },


            _checkBuyer: function (buyer) {
                var keys = Object.keys(buyer);
                var result = true;

                keys.forEach(function (key) {
                    if (buyer[key]) {
                        return;
                    }
                    result = false;
                });

                return result;
            },
            _getSAuthKey: function (serialNumber) {
                return this.SAUTH_KEY + '_' + serialNumber;
            },
            _getSsignatureKey: function (serialNumber) {
                return this.SSIGNATURE_KEY + '_' + serialNumber;
            },
            _getSDToken: function (serialNumber) {
                return this.SDTOKEN_KEY + '_' + serialNumber;
            },
            _getCurrentDate: function () {
                return new Date();
            },

            /**
             * @private _createAuthPkcs7
             * @param {*} vo 
             * @param {*} success 
             * @param {*} fail 
             */
            _loadAuthId: function (vo, success, error, fail) {
                var self = this;

                self.loadAuthId(vo, function (data) {
                    self.laodEImzoKey(vo, function (id) {
                        self.createPkcs7(id, self._createPkcsData(data.authId), function (pkcs7) {
                            // self.createPkcs7(id, vo.TIN, function (pkcs7) {
                            //     self.aaa = pkcs7;
                            // }, function(e) {
                            //     console.error(e);
                            // });
                            self._callFunc(success, pkcs7, data.authId, id, vo);
                        }, error, fail);
                    }, fail);
                });
            },

            _getDToken: function (id, authId, vo, success, fail) {
                var self = this;

                self.createPkcs7(id, self._createPkcsData(authId),
                    function (pkcs7) {

                        // self._createSignature(vo);

                        self._callFunc(success, pkcs7, vo);
                    },
                    function (e, r) {
                        self._callFunc(fail, e, r);
                    }
                );
            },

            /**
             * leads to the format required for sending in loadDidoxKey
             * @private _createPkcsData
             * @param {String} authId 
             * @returns {String}
             */
            _createPkcsData: function (authId) {
                // return "{ authId: '" + authId + "' }";
                return JSON.stringify({
                    authId: authId
                });
            },

            _isFunction: function (func) {
                return typeof func === 'function';
            },

            /**
             * @private _callFunc
             * @param {Function} func 
             * @param  {...any} args function arguments
             * @returns {*}
             */
            _callFunc: function (func, ...args) {
                helper.callFunc(func, ...args);
            },

            _uiAppdateApp: function () {
                Swal.fire({
                    icon: 'warning',
                    text: this.errorUpdateApp,
                });
            },

            _uiShowMessage: function (msg) {
                // alert(msg);
                App.showMessage(msg);
            },

            _uiNotLoaded: function (e) {
                if (e) {
                    this._wsError(e);
                } else {
                    this._uiShowMessage(this.errorBrowserWS);
                }
            },
            _wsError: function (e) {
                if (e) {
                    this._uiShowMessage(this.errorCAPIWS + " : " + e);
                } else {
                    this._uiShowMessage(this.errorBrowserWS);
                }
            },
        }
    
        return DocsSign;
    }


    function getDocConstructor () {
        function DocConstrucor () {

        }

        DocConstrucor.prototype = {

        }

        return DocConstrucor;
    }

})();