'use strict';

angular.module('yololiumApp')
  .controller('LoginController3', [
    '$scope'
  , '$q'
  , '$timeout'
  , '$modalInstance'
  , 'Oauth3'
  , 'DaplieApiSession'
  , 'DaplieApiRequest'
  , 'LdsAccount'
  , 'myLoginOptions'
  , function (
      $scope
    , $q
    , $timeout
    , $modalInstance
    , Oauth3
    , Oauth3ApiSession
    , Oauth3ApiRequest
    , LdsAccount
    , opts
    ) {
    opts = opts || {};
    var scope = this;
    var secretMinLen = scope.secretMinLength = Oauth3ApiSession.secretMinLength;
    //var usernameMinLen = Oauth3ApiSession.usernameMinLength;
    var mySession;

    scope.hideSocial = opts.hideSocial;
    scope.flashMessage = opts.flashMessage;
    scope.flashMessageClass = opts.flashMessageClass;

    scope.delta = { localLogin: {} };

    function onDaplieLogin(oauth3Session) {
      console.log('DEBUG onLogin');
      console.log(oauth3Session);
      // TODO if there is not a default account, show user-switching screen
      // this will close both on user/pass and social login
      scope.flashMessage = "You've logged in. Please wait while we download some ward and stake data...";
      scope.flashMessageClass = 'alert-info';
      return Oauth3ApiRequest.profile(oauth3Session).then(function (profile) {
        console.log('DEBUG profile');
        console.log(profile);

        $modalInstance.close(oauth3Session);
        /*
        return LdsAccount.verifyAccount(ldsSession, profile).then(function () {
          scope.flashMessage = "Done!";
          scope.flashMessageClass = 'alert-success';
          console.log('DEBUG verifiedAccount');
          $modalInstance.close(ldsSession);
        });
        */
      });
    }

    function handleLoginException(err) {
      scope.formState = 'login';

      console.error("[Uknown Error] Either 'resource owner password' or 'delegated' login");
      console.warn(err.stack);
      scope.flashMessage = err.message || err.code;
      scope.flashMessageClass = "alert-danger";
    }

    function handleSuccess(session) {
      return Oauth3ApiSession.requireAccount(session).then(onDaplieLogin, function (err) {
        if ('E_NO_LDSACCOUNT' !== err.code) {
          throw err;
        }

        scope.hideSocial = true;
        scope.flashMessage = err.message;
        scope.flashMessageClass = "alert-warning";
      }).catch(handleLoginException);
    }

    function handleLoginError(err) {
      console.error('handleLoginError');
      console.error(err);
      console.warn(err.stack);
      if (!err.message) {
        throw err;
      }

      scope.formState = 'login';

      scope.flashMessage = err.message || err.code;
      scope.flashMessageClass = "alert-warning";

      throw err;
    }

    scope.loginStrategies = [
      { label: 'Facebook'
      , name: 'facebook'
      , faImage: ""
      , faClass: "fa-facebook"
      , btnClass: "btn-facebook"
      , login: function () {
          var providerUri = (window.location.host +  window.location.pathname).replace(/\/$/g, '');
          var providerApiUri = 'https://oauth3.org';

          return Oauth3ApiSession.login({
            providerUri: providerUri // 'daplie.com/connect'
          , scope: [ 'email' ]
          , redirectUri: 'https://' + providerUri + '/oauth3.html'
          , popup: true
            // TODO XXX use whatever variable it is for apiHost
          , authorizationRedirect: providerApiUri + '/api/org.oauth3.consumer/authorization_redirect/facebook.com'
          }).then(handleSuccess, handleLoginError).catch(handleLoginException);
        }
      }
    , { label: 'Google+'
      , name: 'google'
      , faImage: ""
      , faClass: "fa-google-plus"
      , btnClass: "btn-google-plus"
      , login: function () {
          return Oauth3ApiSession.logins.authorizationRedirect({
            providerUri: 'google.com'
          , scope: [ 'https://www.googleapis.com/auth/plus.login' ]
          , redirectUri: 'https://beta.ldsconnect.org/oauth3.html'
          , popup: true
          }).then(handleSuccess, handleLoginError).catch(handleLoginException);
        }
      }

    /*
    , { label: 'LDS.org Account'
      , faImage: "images/moroni-128px.png"
      , faClass: ""
      , btnClass: "openid"
      , login: scope.loginWithLdsconnect
      }
    */
    ];

    scope.hideSocial = opts.hideSocial;
    scope.flashMessage = opts.flashMessage;
    scope.flashMessageClass = opts.flashMessageClass;

    // This dialog is opened to update necessary account details
    // It should be passed options to inform the dialog which
    // missing fields are necessary to show at this time
    //
    // Examples:
    // we want to get facebook but haven't connected yet, so we should show the connection dialog
    // we just logged in for the first time and don't have an account or a local login
    function onLogout() {
      scope.session = null;
      scope.account = null;
      scope.accounts = null;
    }

    function onLogin(session) {
      // session is always ensured as part of login
      mySession = session;

      var defaultAction = '';
      var emails = [];

      scope.account = scope.account || mySession.account || {};
      if (scope.account.id) {
        defaultAction = 'update';
      }

      scope.formAction = scope.formAction || defaultAction;

      scope.account = scope.account || {};
      scope.delta = scope.delta || {};
      scope.deltaEmail = { type: 'email' };
      scope.deltaPhone = { type: 'phone' };
      scope.delta.localLogin = scope.delta.localLogin || {};
      scope.logins = mySession.logins.map(function (login) {
        return {
          comment: ('local' === (login.provider || login.type)) ? (login.uid || 'username') : login.provider
        , id: login.id
        , uid: login.uid
        , provider: login.provider
        , type: login.type
        , link: true
        };
      });

      mySession.logins.some(function (login) {
        if ('local' === (login.type || login.provider)) {
          scope.account.localLoginId = login.id;
          scope.delta.localLogin.id = login.id;
        }
      });

      // login is always ensured prior to account
      mySession.logins.forEach(function (l) {
        (l.emails||[]).forEach(function (email) {
          if (email && email.value) {
            emails.push(email);
          }
        });
      });

      // TODO combo box for creating new logins
      scope.emails = emails;
      scope.deltaEmail.node = (emails[0] || {}).value;

      if (!scope.deltaEmail.node) {
        mySession.logins.some(function (login) {
          scope.deltaEmail.node = (login.emails && login.emails[0] || {}).value;
          return scope.deltaEmail.node;
        });
      }

      /*
      if (mySession.logins.length) {
        scope.formAction = 'create';
      }
      */

      // TODO check mySession
      if (mySession.logins.length >= 2) {
        scope.recoverable = true;
      }
    }

    scope.checkTotp = function (nodeObj) {
      var tokenLen = 6;
      var len = (nodeObj.totp||'').replace(/\D/g, '').length;

      if (len === tokenLen) {
        nodeObj.totpMessage = 'So far, so good.';
        return;
      }

      nodeObj.totpMessage = 'Token is too short '
        + len + '/' + tokenLen
        + ' (needs to be ' + tokenLen + '+ digits)'
        ;
    };
    scope.checkSecret = function (nodeObj) {
      var len = (nodeObj.secret||'').length;
      var meetsLen = (len >= secretMinLen);

      if (meetsLen) {
        nodeObj.secretMessage = 'Login when ready, captain!';
        return;
      }

      nodeObj.secretMessage = 'Passphrase is too short '
        + len + '/' + secretMinLen
        + ' (needs to be ' + secretMinLen + '+ characters)'
        ;
    };

    scope.submitLogin = function (nodeObj) {
      var promise;
      scope.flashMessage = "";
      scope.flashMessageClass = "alert-danger";

      if (scope._loginPromise) {
        promise = scope._loginPromise;
      } else {
        promise = $q.when();
      }

      // TODO this must be implemented in all platforms
      nodeObj.secret = nodeObj.secret.trim();

      console.log('submitLogin nodeObj', nodeObj);
      if ('create' === scope.formState) {
        nodeObj.kdf = 'PBKDF2';
        nodeObj.bits = 128;
        nodeObj.algo = 'SHA-256';
        nodeObj.iter = Math.floor(Math.random() * 100) + 1001;
      }

      promise = window.getProofOfSecret(nodeObj);

      if ('create' === scope.formState) {
        // TODO redo soft check
        // TODO move to OAuth3
        return promise.then(function (kdf) {
          kdf.secret = null;
          //console.log('Oauth3.logins', Object.keys(Oauth3.logins));
          return Oauth3ApiSession.createLogin(kdf.node, kdf.type || 'email', null, {
            kdf: kdf.kdf
          , algo: kdf.algo
          //, hash: kdf.algo
          , iter: kdf.iter
          , bits: kdf.bits
          , salt: kdf.salt
          , proof: kdf.proof
          //, shadow: kdf.proof
          }, null);
        });
      }

      return promise.then(function (kdf) {
        // TODO change the state to authenticating for social logins as well
        scope.formState = 'authenticating';
        // ALL THE SCOPES!!!
        // TODO
        //return Oauth3.requests.resourceOwnerPassword('https://daplie.com/connect', nodeObj.node, kdf.proof, { scope: '*', appId: 'ID__b5db805e27cc27a0ee8eddf42f46' }).then(function (session) {
        return Oauth3ApiSession.login({
          username: nodeObj.node
        //, usernameType: nodeObj.nodeType
        , password: kdf.proof
        , totp: nodeObj.totp
        //, mfa: kdf.mfa
        , scope: '*'
        }).then(function (session) {
          console.log('[session]', session);
          if (session.error) {
            throw new Error("no oauth3 session");
          }
          return Oauth3ApiSession.requireAccount(session).then(onDaplieLogin);
        }, handleLoginError).catch(handleLoginException);
      });
    };

    scope.checkLdsLogin = function (nodeObj) {
      var username;
      var myPromise;
      var nameError;

      scope.formState = 'login';
      nodeObj.claimable = false;
      nodeObj.message = '';
      scope.flashMessage = '';
      scope.flashMessageClass = "alert-warning";
      username = nodeObj.node;

      $timeout.cancel(scope._loginTimeout);

      if (!username || 'null' === username || 'undefined' === username) {
        myPromise = false;
        scope.formState = 'invalid';
        nodeObj.message = '';
        return;
      }

      // returns true or error object
      nameError = Oauth3ApiSession.validateUsername(nodeObj.node);
      if (nameError.message) {
        myPromise = false;
        scope.formState = 'invalid';
        nodeObj.message = nameError.message;
        return;
      }

      nodeObj.message = 'Checking username...';
      myPromise = scope._loginTimeout = $timeout(function () {
        scope._loginPromise = Oauth3ApiSession.getMeta(nodeObj.node, nodeObj.type || 'email').then(function (kdf) {
          // kdf
          nodeObj.kdf = kdf.kdf;
          nodeObj.algo = kdf.algo;
          nodeObj.bits = kdf.bits;
          nodeObj.iter = kdf.iter;
          nodeObj.salt = kdf.salt;
          scope.showTotp = kdf.totpEnabledAt || kdf.totpEnabled || kdf.totp;

          myPromise = false;
          nodeObj.message = "'" + username + "' is already registered."
            + ' Welcome back!'
            ;
          scope.formState = 'login';
        }, function () {
          // TODO test that error is simply not exists
          // and not a server error
          if (myPromise !== scope._loginTimeout) {
            return;
          }

          scope.formState = 'create';
          nodeObj.message = "'" + username + "' is available!";
        }).catch(function (err) {
          nodeObj.message = '';

          scope.formState = 'login';
          scope.flashMessage = "[Uknown Error] " + err.message
            + " (might need to wait a minute and try again)";
          scope.flashMessageClass = "alert-danger";
          throw err;
        });
      }, 250);

      return scope._loginTimeout;
    };

    //
    // Begin
    //
    //Oauth3ApiSession.onLogin($scope, onDaplieLogin);
    Oauth3ApiSession.onLogout($scope, onLogout);
    //Oauth3ApiSession.checkSession().then(onDaplieLogin, onLogout);
    if (false) {
      // prevent lint warnings until I figure out how I'll use this
      onLogin();
    }
  }]);
