app.factory('Auth', [
  '$rootScope', 'localStorageService', '$location', 'azp@oauth3.org'
, function($rootScope, localStorageService, $location, Oauth3) {

  var dapSession = 'dap-session';
  var dapSessions = 'dap-sessions';

  var Auth = {
    isLoggedIn: function () {
      Auth.restore();

      return Auth.session || false;
    },
    getProfile: function (profile) {
      Auth.restore();

      return Auth.session || false;
    },
    getActiveSessions: function () {
      Auth.restore();

      return Auth.sessions || false;
    }
  , add: function (session) {
      var obj = JSON.parse(localStorage.getItem(dapSessions) || 'null') || {};
      var dapName = 'dap-' + session.subject + '|' + session.issuer;

      console.log('add session', session);

      /*
      Object.keys(Auth.session).forEach(function (key) {
        delete Auth.session[key];
      });
      Object.keys(session).forEach(function (key) {
        Auth.session[key] = session[key];
      });
      */
      Auth.session = session;
      Auth.sessions.push(session);

      localStorage.setItem(dapName, JSON.stringify(session));
      localStorage.setItem(dapSession, dapName);
      obj[dapName] = Date.now();
      localStorage.setItem(dapSessions, JSON.stringify(obj));
    }
  , restore: function () {
      var dapName = localStorage.getItem(dapSession);
      Auth.sessions.length = 0; // don't overwrite with a new array, keep original references

      (Object.keys(JSON.parse(localStorage.getItem(dapSessions) || 'null') || {})).forEach(function (name) {
        var session = JSON.parse(localStorage.getItem(name) || 'null');

        if (session) {
          session.email = session.subject;
        }
        if (!session.issuer) {
          console.error(session);
          throw new Error('restored session without audience');
        }

        if (dapName === name) {
          Auth.session = session;
        }

        Auth.sessions.push(session);
      });

      return Auth.session;
    }
  , select: function (session) {
      if (!session.issuer) {
        throw new Error("session doesn't have an issuer");;
      }

      var name = session.token.sub + '@' + session.token.iss;
      var promise;

      if (!Auth._oauth3s[name]) {
        Auth._oauth3s[name] = Oauth3.create(window.location);
        promise = Auth._oauth3s[name].init({
          location: location
        , issuer: session.issuer
        , audience: session.audience || session.issuer
        , session: session
        }).then(function () {
          console.log('a Auth._oauth3s[name]', Auth._oauth3s[name]);
          return Auth._oauth3s[name];
        });
      } else {
        console.log('b Auth._oauth3s[name]', Auth._oauth3s[name]);
        promise = Oauth3.PromiseA.resolve(Auth._oauth3s[name]);
      }

      console.log('session.issuer:', session.issuer);
      console.log('session.subject:', session.subject);
      console.log('session:', session);

      promise.then(function (oauth3) {
        Auth.session = session;
        Auth.oauth3 = oauth3;
      })

      return promise;
    }
  , signOut: function () {
      var session = Auth.session;
      var dapName = 'dap-' + session.subject + '|' + session.issuer;

      // TODO logout url should be created upon login and remain fixed throughout the duration of the session (or on session restoration)
      return Auth.oauth3.logout().then(function () {
        var obj = JSON.parse(localStorage.getItem(dapSessions) || '{}');
        delete obj[dapName];
        var newDapName = Object.keys(obj).sort(function (a, b) { return obj[a] - obj[b]; })[0];

        localStorage.setItem(dapSession, newDapName);
        localStorage.setItem(dapSessions, JSON.stringify(obj));
        localStorage.removeItem(dapName);

        if (!newDapName) {
          localStorage.removeItem(dapSession);
        }

        return Auth.restore();
      });
      // localStorage.clear();
    }
  , _oauth3s: {}
  , sessions: []
  , session: null
  , oauth3: null
  };

  Auth.oauth3 = Oauth3.create(window.location);

  return Auth;
}]);