'use strict';

/* global tld */

// create main application module
var app = angular.module('Application', ['angular-md5', 'ui-notification']);

app.filter('zoneName', function () {
    return function (domain) {
        return tld.getDomain(domain);
    };
});

app.controller('SetupDNSController', ['$scope', '$http', '$timeout', 'Client', function ($scope, $http, $timeout, Client) {
    var search = decodeURIComponent(window.location.search).slice(1).split('&').map(function (item) { return item.split('='); }).reduce(function (o, k) { o[k[0]] = k[1]; return o; }, {});

    $scope.state = null; // 'initialized', 'waitingForDnsSetup', 'waitingForBox'
    $scope.error = null;
    $scope.provider = '';
    $scope.showDNSSetup = false;
    $scope.instanceId = '';
    $scope.explicitZone = search.zone || '';
    $scope.isEnterprise = !!search.enterprise;
    $scope.isDomain = false;
    $scope.isSubdomain = false;

    // If we migrate the api origin we have to poll the new location
    if (search.admin_fqdn) Client.apiOrigin = 'https://' + search.admin_fqdn;

    $scope.$watch('dnsCredentials.domain', function (newVal) {
        if (!newVal) {
            $scope.isDomain = false;
            $scope.isSubdomain = false;
        } else if (!tld.getDomain(newVal) || newVal[newVal.length-1] === '.') {
            $scope.isDomain = false;
            $scope.isSubdomain = false;
        } else {
            $scope.isDomain = true;
            $scope.isSubdomain = tld.getDomain(newVal) !== newVal;
        }
    });

    // keep in sync with domains.js
    $scope.dnsProvider = [
        { name: 'AWS Route53', value: 'route53' },
        { name: 'Cloudflare (DNS only)', value: 'cloudflare' },
        { name: 'Digital Ocean', value: 'digitalocean' },
        { name: 'Google Cloud DNS', value: 'gcdns' },
        { name: 'Wildcard', value: 'wildcard' },
        { name: 'Manual (not recommended)', value: 'manual' },
        { name: 'No-op (only for development)', value: 'noop' }
    ];
    $scope.dnsCredentials = {
        error: null,
        busy: false,
        domain: '',
        accessKeyId: '',
        secretAccessKey: '',
        gcdnsKey: { keyFileName: '', content: '' },
        digitalOceanToken: '',
        provider: 'route53'
    };

    function readFileLocally(obj, file, fileName) {
        return function (event) {
            $scope.$apply(function () {
                obj[file] = null;
                obj[fileName] = event.target.files[0].name;

                var reader = new FileReader();
                reader.onload = function (result) {
                    if (!result.target || !result.target.result) return console.error('Unable to read local file');
                    obj[file] = result.target.result;
                };
                reader.readAsText(event.target.files[0]);
            });
        };
    }

    document.getElementById('gcdnsKeyFileInput').onchange = readFileLocally($scope.dnsCredentials.gcdnsKey, 'content', 'keyFileName');

    $scope.setDnsCredentials = function () {
        $scope.dnsCredentials.busy = true;
        $scope.dnsCredentials.error = null;
        $scope.error = null;

        var provider = $scope.dnsCredentials.provider;

        var data = {
            providerToken: $scope.instanceId
        };

        // special case the wildcard provider
        if (provider === 'wildcard') {
            provider = 'manual';
            data.wildcard = true;
        }

        if (provider === 'route53') {
            data.accessKeyId = $scope.dnsCredentials.accessKeyId;
            data.secretAccessKey = $scope.dnsCredentials.secretAccessKey;
        } else if (provider === 'gcdns'){
            try {
                var serviceAccountKey = JSON.parse($scope.dnsCredentials.gcdnsKey.content);
                data.projectId = serviceAccountKey.project_id;
                data.credentials = {
                    client_email: serviceAccountKey.client_email,
                    private_key: serviceAccountKey.private_key
                };

                if (!data.projectId || !data.credentials || !data.credentials.client_email || !data.credentials.private_key) {
                    throw 'fields_missing';
                }
            } catch(e) {
                $scope.dnsCredentials.error = 'Cannot parse Google Service Account Key';
                $scope.dnsCredentials.busy = false;
                return;
            }
        } else if (provider === 'digitalocean') {
            data.token = $scope.dnsCredentials.digitalOceanToken;
        } else if (provider === 'cloudflare') {
            data.email = $scope.dnsCredentials.cloudflareEmail;
            data.token = $scope.dnsCredentials.cloudflareToken;
        }

        Client.setupDnsConfig($scope.dnsCredentials.domain, $scope.explicitZone, provider, data, function (error) {
            if (error && error.statusCode === 403) {
                $scope.dnsCredentials.busy = false;
                $scope.error = 'Wrong instance id provided.';
                return;
            } else if (error) {
                $scope.dnsCredentials.busy = false;
                $scope.dnsCredentials.error = error.message;
                return;
            }

            waitForDnsSetup();
        });
    };

    function waitForDnsSetup() {
        $scope.state = 'waitingForDnsSetup';

        Client.getStatus(function (error, status) {
            // webadminStatus.dns is intentionally not tested. it can be false if dns creds are invalid
            // runConfigurationChecks() in main.js will pick the .dns and show a notification
            if (!error && status.adminFqdn && status.webadminStatus.tls) {
                window.location.href = 'https://' + status.adminFqdn + '/setup.html';
            }

            setTimeout(waitForDnsSetup, 5000);
        });
    }

    function initialize() {
        Client.getStatus(function (error, status) {
            if (error) {
                // During domain migration, the box code restarts and can result in getStatus() failing temporarily
                console.error(error);
                $scope.state = 'waitingForBox';
                return $timeout(initialize, 3000);
            }

            // domain is currently like a lock flag
            if (status.adminFqdn) return waitForDnsSetup();

            if (status.provider === 'digitalocean') $scope.dnsCredentials.provider = 'digitalocean';
            if (status.provider === 'gcp') $scope.dnsCredentials.provider = 'gcdns';
            if (status.provider === 'ami') {
                // remove route53 on ami
                $scope.dnsProvider.shift();
                $scope.dnsCredentials.provider = 'wildcard';
            }

            $scope.instanceId = search.instanceId;
            $scope.provider = status.provider;
            $scope.state = 'initialized';
        });
    }

    initialize();
}]);
