backupApp.directive('backupEditStepOne', function (gettextCatalog) {
    return {
        restrict: 'E',
        scope: {
            backup: '=backup',
            options: '=options',
            setBuilduriFn: '&',
            isValid: '=',
        },
        templateUrl: 'templates/backup-edit/step1.html?v=1.0.2.2',
        controller: function ($scope, $routeParams, AppService, AppUtils, SystemInfo, EditUriBackendConfig, DialogService) {

            var scope = $scope;
            scope.AppUtils = AppUtils;

            scope.isEditMode = $routeParams.backupid !== undefined;
            $scope.isServerPathVerified = $scope.isEditMode;
            
            $scope.RepeatPasshrase = '';
            $scope.PasswordStrength = 'unknown';

            let validatedPath = null;

            const builduri = function (callback) {

                function validationCompleted() {
                    if (EditUriBackendConfig.builders[scope.Backend.Key] == null)
                        callback(EditUriBackendConfig.defaultbuilder(scope));
                    else
                        callback(EditUriBackendConfig.builders[scope.Backend.Key](scope));
                }

                if (EditUriBackendConfig.validaters[scope.Backend.Key] == null)
                    EditUriBackendConfig.defaultvalidater(scope, validationCompleted);
                else
                    EditUriBackendConfig.validaters[scope.Backend.Key](scope, validationCompleted);
            };


            function performConnectionTest(uri) {

                var hasTriedCreate = false;
                var hasTriedCert = false;
                var hasTriedMozroots = false;
                var hasTriedHostkey = false;
                var dlg = null;
                var testConnection = function () {
                    scope.isServerPathVerified = false
                    scope.Testing = true;
                    if (dlg != null)
                        dlg.dismiss();

                    dlg = DialogService.dialog(gettextCatalog.getString('Testing ...'), gettextCatalog.getString('Testing connection ...'), [], null, function () {
                        AppService.post('/remoteoperation/test', uri).then(function (data) {
                            scope.Testing = false;
                            dlg.dismiss();

                            if (!data.data.FolderExists && $routeParams.backupid == null && $scope.Path !== validatedPath) {
                                createFolder()
                                return
                            }
                            else if (!data.data.FolderExists && $routeParams.backupid > 0) {
                                DialogService.dialog(gettextCatalog.getString('Error'), gettextCatalog.getString('The backup has been wrongly setup (the targeted folder is not accessible). Try to delete it and recreate it.'))
                                return
                            }
                            else if (data.data.FolderExists && $routeParams.backupid == null && $scope.Path !== validatedPath) {
                                DialogService.dialog(gettextCatalog.getString('Error'), gettextCatalog.getString('The Folder already exists and used by another job.'))

                                return
                            }
                            else if (!data.data.FolderExists) {
                                createFolder()
                                // DialogService.dialog(gettextCatalog.getString('Error') , gettextCatalog.getString('The targeted Folder does not exists.'))
                                return
                            }

                            scope.isServerPathVerified = true
                            if (EditUriBackendConfig.testers[scope.Backend.Key] != null)
                                EditUriBackendConfig.testers[scope.Backend.Key](scope, function () {
                                    DialogService.dialog(gettextCatalog.getString('Success'), gettextCatalog.getString('Connection worked!'));
                                });
                            else
                                DialogService.dialog(gettextCatalog.getString('Success'), gettextCatalog.getString('Connection worked!'));

                        }, handleError);
                    });

                };

                const createFolder = function () {
                    hasTriedCreate = true;
                    scope.Testing = true;
                    AppService.post('/remoteoperation/create', uri)
                        .then(_ => {
                            validatedPath = $scope.Path;
                            testConnection();
                        }, handleError)
                };

                const appendApprovedCert = function (hash) {
                    hasTriedCert = true;
                    for (const n in scope.AdvancedOptions) {
                        if (scope.AdvancedOptions[n].indexOf('--accept-specified-ssl-hash=') == 0) {
                            const certs = scope.AdvancedOptions[n].substr('--accept-specified-ssl-hash='.length).split(',');
                            for (const i in certs)
                                if (certs[i] == hash)
                                    return;

                            scope.AdvancedOptions[n] += ',' + hash;
                            return;
                        }
                    }

                    scope.AdvancedOptions.push('--accept-specified-ssl-hash=' + hash);
                };

                const askApproveCert = function (hash) {
                    DialogService.dialog(gettextCatalog.getString('Trust server certificate?'), gettextCatalog.getString('The server certificate could not be validated.\nDo you want to approve the SSL certificate with the hash: {{hash}}?', { hash: hash }), [gettextCatalog.getString('No'), gettextCatalog.getString('Yes')], function (ix) {
                        if (ix == 1) {
                            appendApprovedCert(hash);
                            builduri(function (res) {
                                uri = res;
                                testConnection();
                            });
                        }
                    });
                };

                const hasCertApproved = function (hash) {
                    for (const n in scope.AdvancedOptions) {
                        if (scope.AdvancedOptions[n].indexOf('--accept-specified-ssl-hash=') == 0) {
                            const certs = scope.AdvancedOptions[n].substr('--accept-specified-ssl-hash='.length).split(',');
                            for (const i in certs)
                                if (certs[i] == hash)
                                    return true;

                            break;
                        }
                    }

                    return false;
                };

                const handleError = function (data) {

                    scope.Testing = false;
                    if (dlg != null)
                        dlg.dismiss();

                    var message = data.statusText;

                    // if (!hasTriedCreate && message == 'missing-folder')
                    // {
                    //     var folder = scope.Folder;
                    //     if ((folder || "") == "")
                    //         folder = scope.Path;
                    //     if ((folder || "") == "")
                    //         folder = '';

                    //     DialogService.dialog(gettextCatalog.getString('Create folder?'), gettextCatalog.getString('The folder {{folder}} does not exist.\nCreate it now?', { folder: folder }), [gettextCatalog.getString('No'), gettextCatalog.getString('Yes')], function(ix) {
                    //         if (ix == 1)
                    //             createFolder();
                    //     });
                    // }
                    // else
                    if (!hasTriedCert && message.indexOf('incorrect-cert:') == 0) {
                        var hash = message.substr('incorrect-cert:'.length);
                        if (hasCertApproved(hash)) {
                            if (data.data != null && data.data.Message != null)
                                message = data.data.Message;

                            DialogService.dialog(gettextCatalog.getString('Error'), gettextCatalog.getString('Failed to connect: ') + message);
                            return;
                        }

                        if ($scope.SystemInfo.MonoVersion != null && !hasTriedMozroots) {

                            hasTriedMozroots = true;

                            AppService.post('/webmodule/check-mono-ssl', { 'mono-ssl-config': 'List' }).then(function (data) {
                                if (data.data.Result.count == 0) {
                                    if (confirm(gettextCatalog.getString('You appear to be running Mono with no SSL certificates loaded.\nDo you want to import the list of trusted certificates from Mozilla?'))) {
                                        scope.Testing = true;
                                        AppService.post('/webmodule/check-mono-ssl', { 'mono-ssl-config': 'Install' }).then(function (data) {
                                            scope.Testing = false;
                                            if (data.data.Result.count == 0) {
                                                DialogService.dialog(gettextCatalog.getString('Import failed'), gettextCatalog.getString('Import completed, but no certificates were found after the import'));
                                            } else {
                                                testConnection();
                                            }
                                        }, function (resp) {

                                            scope.Testing = false;
                                            message = resp.statusText;
                                            if (data.data != null && data.data.Message != null)
                                                message = data.data.Message;

                                            DialogService.dialog(gettextCatalog.getString('Error'), gettextCatalog.getString('Failed to import: ') + message);

                                        });
                                    }
                                    else {
                                        askApproveCert(hash);
                                    }
                                } else {
                                    askApproveCert(hash);
                                }

                            }, AppUtils.connectionError);

                        }
                        else {
                            askApproveCert(hash);
                        }
                    }
                    else if (!hasTriedHostkey && message.indexOf('incorrect-host-key:') == 0) {
                        var re = /incorrect-host-key\s*:\s*"([^"]*)"(,\s*accepted-host-key\s*:\s*"([^"]*)")?/;
                        var m = re.exec(message);
                        var key = null;
                        var prev = null;
                        if (m != null) {
                            key = m[1] || '';
                            prev = m[3] || '';
                        }

                        if ((key || '').trim().length == 0 || key == prev) {
                            if (data.data != null && data.data.Message != null)
                                message = data.data.Message;

                            DialogService.dialog(gettextCatalog.getString('Error'), gettextCatalog.getString('Failed to connect: ') + message);
                        }
                        else {
                            var message = ((prev || '').trim().length == 0) ?
                                (gettextCatalog.getString('No certificate was specified previously, please verify with the server administrator that the key is correct: {{key}} \n\nDo you want to approve the reported host key?', { key: key }))
                                :
                                (gettextCatalog.getString('The host key has changed, please check with the server administrator if this is correct, otherwise you could be the victim of a MAN-IN-THE-MIDDLE attack.\n\nDo you want to REPLACE your CURRENT host key "{{prev}}" with the REPORTED host key: {{key}}?', { prev: prev, key: key }));

                            // DialogService.dialog(gettextCatalog.getString('Trust host certificate?'), message, [gettextCatalog.getString('No'), gettextCatalog.getString('Yes')], function(ix) {
                            //     if (ix == 1) {
                            hasTriedHostkey = true;
                            for (var n in scope.AdvancedOptions) {
                                if (scope.AdvancedOptions[n].indexOf('--ssh-fingerprint=') == 0) {
                                    scope.AdvancedOptions.splice(n, 1);
                                    break;
                                }
                            }

                            scope.AdvancedOptions.push('--ssh-fingerprint=' + key);
                            builduri(function (res) {
                                uri = res;
                                testConnection();
                            });
                            //     }
                            // });

                        }
                    }
                    else {
                        if (data.data != null && data.data.Message != null)
                            message = data.data.Message;

                        DialogService.dialog(gettextCatalog.getString('Error'), gettextCatalog.getString('Failed to connect: ') + message);
                    }
                };

                testConnection();
            }

            $scope.changeConfiguration = function () {
                $scope.isServerPathVerified = false;
            }

            $scope.testConnection = function () {
                if ($scope.Path !== '') {
                    builduri(performConnectionTest);
                }
            };

            $scope.contains_value = AppUtils.contains_value;

            $scope.$watch('Backend', function () {
                if (scope.Backend == null) {
                    $scope.TemplateUrl = null;
                    $scope.AdvanceOptionList = null;
                    return;
                }

                var opts = angular.copy(scope.Backend.Options || []);
                for (var n in opts)
                    opts[n].Category = scope.Backend.DisplayName;

                for (var m in SystemInfo.state.ConnectionModules) {
                    var t = angular.copy(SystemInfo.state.ConnectionModules[m].Options);
                    for (var n in t)
                        t[n].Category = SystemInfo.state.ConnectionModules[m].DisplayName;
                    opts.push.apply(opts, t);
                }

                $scope.AdvanceOptionList = opts;
                scope.SupportsSSL = false;
                for (var n in scope.Backend.Options)
                    if (scope.Backend.Options[n].Name == 'use-ssl')
                        scope.SupportsSSL = true;

                scope.TemplateUrl = EditUriBackendConfig.templates[scope.Backend.Key];
                if (scope.TemplateUrl == null)
                    scope.TemplateUrl = EditUriBackendConfig.defaulttemplate;

                if (EditUriBackendConfig.loaders[scope.Backend.Key] == null)
                    return;

                EditUriBackendConfig.loaders[scope.Backend.Key](scope);
            });

            var reparseuri = function () {
                scope.Backend = scope.DefaultBackend;

                if (!scope.backup)
                {
                    console.log(scope)
                    return;
                }

                var parts = AppUtils.decode_uri(scope.backup.TargetURL);

                for (var n in scope.SystemInfo.GroupedBackendModules) {
                    if (scope.SystemInfo.GroupedBackendModules[n].Key == parts['backend-type']) {
                        scope.Backend = $scope.SystemInfo.GroupedBackendModules[n];
                        break;
                    }

                    if ((scope.SystemInfo.GroupedBackendModules[n].Key + 's') == parts['backend-type']) {
                        var hasssl = false;
                        var bk = scope.SystemInfo.GroupedBackendModules[n];

                        for (var o in bk.Options) {
                            if (bk.Options[o].Name == 'use-ssl') {
                                hasssl = true;
                                break;
                            }
                        }

                        if (hasssl) {
                            scope.Backend = bk;
                            parts['--use-ssl'] = true;
                            break;
                        }
                    }
                }


                scope.Username = parts['--auth-username'];
                scope.Password = parts['--auth-password'];
                scope.UseSSL = parts['--use-ssl'];
                scope.Port = parts['server-port'];
                scope.Server = parts['server-name'];
                scope.Path = parts['server-path'];
                if (scope.backup.TargetFolderPathPrefix !== undefined) {
                    scope.folderPathPrefix = scope.backup.TargetFolderPathPrefix;
                    if (scope.Path !== undefined) {
                        scope.Path = scope.Path.replace(scope.backup.TargetFolderPathPrefix, '');
                    }
                }

                if (scope.Backend != null && scope.uri != null && EditUriBackendConfig.parsers[scope.Backend.Key])
                    EditUriBackendConfig.parsers[scope.Backend.Key](scope, parts['backend-type'], parts['server-name'], parts['server-path'], parts['server-port'], parts);

                delete parts['--auth-username'];
                delete parts['--auth-password'];
                delete parts['--use-ssl'];
                scope.AdvancedOptions = AppUtils.serializeAdvancedOptionsToArray(parts);
            };

            $scope.SystemInfo = SystemInfo.watch($scope, function () {
                for (var n in scope.SystemInfo.GroupedBackendModules)
                    if (scope.SystemInfo.GroupedBackendModules[n].Key == EditUriBackendConfig.defaultbackend)
                        scope.DefaultBackend = scope.SystemInfo.GroupedBackendModules[n];

                reparseuri();
            });
            $scope.$watch('backup.TargetURL', reparseuri);



            function computePassPhraseStrength() {

                const strengthMap = {
                    'x': gettextCatalog.getString("Passphrases do not match"),
                    0: gettextCatalog.getString("Useless"),
                    1: gettextCatalog.getString("Very weak"),
                    2: gettextCatalog.getString("Weak"),
                    3: gettextCatalog.getString("Strong"),
                    4: gettextCatalog.getString("Very strong")
                };

                const passphrase = scope.options == null ? '' : scope.options['passphrase'] ?? '';

                if (scope.RepeatPasshrase != passphrase)
                    scope.PassphraseScore = 'x';
                else if ((passphrase || '') == '')
                    scope.PassphraseScore = '';
                else
                    scope.PassphraseScore = (zxcvbn(passphrase.substring(0, 100)) || { 'score': -1 }).score;

                scope.PassphraseScoreString = strengthMap[scope.PassphraseScore];
                isStep1Valid();
            }

            function isStep1Valid() {
                scope.isValid = scope.backup?.Name !== undefined
                    && scope.backup?.Name != ''
                    && scope.options
                    && scope.RepeatPasshrase == (scope.options['passphrase'] ?? '')
                    && scope.isServerPathVerified
                    ;
            }

            

            $scope.generatePassphrase = function () {
                this.Options["passphrase"] = this.RepeatPasshrase = AppUtils.generatePassphrase();
                this.ShowPassphrase = true;
                this.HasGeneratedPassphrase = true;
            };

            $scope.togglePassphraseVisibility = function () {
                this.ShowPassphrase = !this.ShowPassphrase;
            };

            $scope.setBuilduriFn({ builduriFn: builduri });


            $scope.$watch('options["passphrase"]', () => {
                if(scope.RepeatPasshrase === '' && scope.options != undefined)
                {
                    scope.RepeatPasshrase = scope.options["passphrase"];
                }
                computePassPhraseStrength();
                isStep1Valid();
            });
            $scope.$watch('RepeatPasshrase', computePassPhraseStrength);
            $scope.$watch('backup.Name', isStep1Valid);
            $scope.$watch('isServerPathVerified', isStep1Valid);
        }
    };
});
