(function() {
  'use strict';
  window.Whisper = window.Whisper || {};

  var Steps = {
    INSTALL_SIGNAL: 2,
    SCAN_QR_CODE: 3,
    ENTER_NAME: 4,
    PROGRESS_BAR: 5,
    TOO_MANY_DEVICES: 'TooManyDevices',
    NETWORK_ERROR: 'NetworkError',
  };

  var DEVICE_NAME_SELECTOR = 'input.device-name';
  var CONNECTION_ERROR = -1;
  var TOO_MANY_DEVICES = 411;

  Whisper.InstallView = Whisper.View.extend({
    templateName: 'link-flow-template',
    className: 'main full-screen-flow',
    events: {
      'click .try-again': 'connect',
      'click .finish': 'finishLinking',
      // the actual next step happens in confirmNumber() on submit form #link-phone
    },
    initialize: function(options) {
      options = options || {};

      this.selectStep(Steps.SCAN_QR_CODE);
      this.connect();
      this.on('disconnected', this.reconnect);

      // Keep data around if it's a re-link, or the middle of a light import
      this.shouldRetainData =
        Whisper.Registration.everDone() || options.hasExistingData;
    },
    render_attributes: function() {
      var errorMessage;

      if (this.error) {
        if (
          this.error.name === 'HTTPError' &&
          this.error.code == TOO_MANY_DEVICES
        ) {
          errorMessage = i18n('installTooManyDevices');
        } else if (
          this.error.name === 'HTTPError' &&
          this.error.code == CONNECTION_ERROR
        ) {
          errorMessage = i18n('installConnectionFailed');
        } else if (this.error.message === 'websocket closed') {
          // AccountManager.registerSecondDevice uses this specific
          //   'websocket closed' error message
          errorMessage = i18n('installConnectionFailed');
        }

        return {
          isError: true,
          errorHeader: 'Something went wrong!',
          errorMessage,
          errorButton: 'Try again',
        };
      }

      return {
        isStep3: this.step === Steps.SCAN_QR_CODE,
        linkYourPhone: i18n('linkYourPhone'),
        signalSettings: i18n('signalSettings'),
        linkedDevices: i18n('linkedDevices'),
        androidFinalStep: i18n('plusButton'),
        appleFinalStep: i18n('linkNewDevice'),

        isStep4: this.step === Steps.ENTER_NAME,
        chooseName: i18n('chooseDeviceName'),
        finishLinkingPhoneButton: i18n('finishLinkingPhone'),

        isStep5: this.step === Steps.PROGRESS_BAR,
        syncing: i18n('initialSync'),
      };
    },
    selectStep: function(step) {
      this.step = step;
      this.render();
    },
    connect: function() {
      this.error = null;
      this.selectStep(Steps.SCAN_QR_CODE);
      this.clearQR();
      if (this.timeout) {
        clearTimeout(this.timeout);
        this.timeout = null;
      }

      var accountManager = getAccountManager();

      accountManager
        .registerSecondDevice(
          this.setProvisioningUrl.bind(this),
          this.confirmNumber.bind(this)
        )
        .catch(this.handleDisconnect.bind(this));
    },
    handleDisconnect: function(e) {
      console.log('provisioning failed', e.stack);

      this.error = e;
      this.render();

      if (e.message === 'websocket closed') {
        this.trigger('disconnected');
      } else if (
        e.name !== 'HTTPError' ||
        (e.code !== CONNECTION_ERROR && e.code !== TOO_MANY_DEVICES)
      ) {
        throw e;
      }
    },
    reconnect: function() {
      if (this.timeout) {
        clearTimeout(this.timeout);
        this.timeout = null;
      }
      this.timeout = setTimeout(this.connect.bind(this), 10000);
    },
    clearQR: function() {
      this.$('#qr img').remove();
      this.$('#qr canvas').remove();
      this.$('#qr .container').show();
      this.$('#qr').removeClass('ready');
    },
    setProvisioningUrl: function(url) {
      if ($('#qr').length === 0) {
        console.log('Did not find #qr element in the DOM!');
        return;
      }

      this.$('#qr .container').hide();
      this.qr = new QRCode(this.$('#qr')[0]).makeCode(url);
      this.$('#qr').removeAttr('title');
      this.$('#qr').addClass('ready');
    },
    setDeviceNameDefault: function() {
      var deviceName = textsecure.storage.user.getDeviceName();

      this.$(DEVICE_NAME_SELECTOR).val(deviceName || window.config.hostname);
      this.$(DEVICE_NAME_SELECTOR).focus();
    },
    finishLinking: function() {
      // We use a form so we get submit-on-enter behavior
      this.$('#link-phone').submit();
    },
    confirmNumber: function(number) {
      var tsp = textsecure.storage.protocol;

      window.removeSetupMenuItems();
      this.selectStep(Steps.ENTER_NAME);
      this.setDeviceNameDefault();

      return new Promise(
        function(resolve, reject) {
          this.$('#link-phone').submit(
            function(e) {
              e.stopPropagation();
              e.preventDefault();

              var name = this.$(DEVICE_NAME_SELECTOR).val();
              name = name.replace(/\0/g, ''); // strip unicode null
              if (name.trim().length === 0) {
                this.$(DEVICE_NAME_SELECTOR).focus();
                return;
              }

              this.selectStep(Steps.PROGRESS_BAR);

              var finish = function() {
                resolve(name);
              };

              // Delete all data from database unless we're in the middle
              //   of a re-link, or we are finishing a light import. Without this,
              //   app restarts at certain times can cause weird things to happen,
              //   like data from a previous incomplete light import showing up
              //   after a new install.
              if (this.shouldRetainData) {
                return finish();
              }

              tsp.removeAllData().then(finish, function(error) {
                console.log(
                  'confirmNumber: error clearing database',
                  error && error.stack ? error.stack : error
                );
                finish();
              });
            }.bind(this)
          );
        }.bind(this)
      );
    },
  });
})();
