(function() {
  'use strict';

  const Defs = {};

  const Statuses = window.Gerrit.Checks.Statuses;
  const StatusPriorityOrder = [
    Statuses.FAILED,
    Statuses.SCHEDULED,
    Statuses.RUNNING,
    Statuses.SUCCESSFUL,
    Statuses.NOT_STARTED,
    Statuses.NOT_RELEVANT,
  ];

  const CHECKS_POLL_INTERVAL_MS = 60 * 1000;

  /**
   * @typedef {{
   *   _number: number,
   * }}
   */
  Defs.Change;
  /**
   * @typedef {{
   *   _number: number,
   * }}
   */
  Defs.Revision;

  const LoadingStatus = {
    LOADING: 0,
    EMPTY: 1,
    RESULTS: 2,
    NOT_CONFIGURED: 3,
  };

  Polymer({
    is: 'gr-checks-view',

    properties: {
      revision: {
        type: Object,
        observer: '_computeCurrentPatchSet',
      },
      change: Object,
      /** @type {function(number, number): !Promise<!Object>} */
      getChecks: Function,
      /** @type {function(string): !Promise<Boolean>} */
      isConfigured: Function,
      /** @type {function(string, string): !Promise<!Object>} */
      pluginRestApi: Object,
      _checks: Object,
      _status: {
        type: Object,
        value: LoadingStatus.LOADING,
      },
      pollChecksInterval: Number,
      visibilityChangeListenerAdded: {
        type: Boolean,
        value: false,
      },
      _createCheckerCapability: {
        type: Boolean,
        value: false,
      },
      _patchSetDropdownItems: {
        type: Array,
        value() { return []; },
      },
      _currentPatchSet: {
        type: Number,
      },
    },

    observers: [
      '_pollChecksRegularly(change, _currentPatchSet, getChecks)',
    ],

    attached() {
      this.pluginRestApi = this.plugin.restApi();
      this._initCreateCheckerCapability();
      this._patchSetDropdownItems = Object.values(this.change.revisions)
          .filter(patch => patch._number !== 'edit')
          .map(patch => {
            return {
              text: 'Patchset ' + patch._number,
              value: patch._number,
            };
          })
          .sort((a, b) => b.value - a.value);
      this._currentPatchSet = this.revision._number;
    },

    detached() {
      clearInterval(this.pollChecksInterval);
      this.unlisten(document, 'visibilitychange', '_onVisibililityChange');
    },

    _computeCurrentPatchSet(revision) {
      this._currentPatchSet = revision._number;
    },

    _handlePatchSetChanged(e) {
      const patchSet = e.detail.value;
      if (patchSet === this._currentPatchSet) return;
      this._currentPatchSet = patchSet;
    },

    _handleCheckersListResize() {
      // Force polymer to recalculate position of overlay when length of
      // checkers changes
      this.$.listOverlay.refit();
    },

    _initCreateCheckerCapability() {
      return this.pluginRestApi.getAccount().then(account => {
        if (!account) { return; }
        return this.pluginRestApi
            .getAccountCapabilities(['checks-administrateCheckers'])
            .then(capabilities => {
              if (capabilities['checks-administrateCheckers']) {
                this._createCheckerCapability = true;
              }
            });
      });
    },

    _handleConfigureClicked() {
      this.$$('gr-checkers-list')._showConfigureOverlay();
    },

    _orderChecks(a, b) {
      if (a.state != b.state) {
        const indexA = StatusPriorityOrder.indexOf(a.state);
        const indexB = StatusPriorityOrder.indexOf(b.state);
        if (indexA != -1 && indexB != -1) {
          return indexA - indexB;
        }
        return indexA == -1 ? 1 : -1;
      }
      if (a.state === Statuses.FAILED) {
        if (a.blocking && b.blocking &&
            a.blocking.length !== b.blocking.length) {
          return a.blocking.length == 0 ? 1 : -1;
        }
      }
      return a.checker_name.localeCompare(b.checker_name);
    },

    _handleRetryCheck(e) {
      const uuid = e.detail.uuid;
      const retryCheck = (change, revision, uuid) => {
        return this.pluginRestApi.post(
            '/changes/' + change + '/revisions/' + revision + '/checks/' + uuid
              + '/rerun'
        );
      };
      retryCheck(this.change._number, this.revision._number, uuid).then(
          res => {
            this._fetchChecks(this.change, this.revision, this.getChecks);
          }, e => {
            console.error(e);
          }
      );
    },

    /**
     * Merge new checks into old checks to maintain showCheckMessage
     * property
     * Loop over checks to make sure no new checks are missed
     * Merge new check object into prev check
     * Remove any check that is not returned the next time
     * Ensure message is updated
     */
    _updateChecks(checks) {
      return checks.map(
          check => {
            const prevCheck = this._checks.find(
                c => { return c.checker_uuid === check.checker_uuid; }
            );
            if (!prevCheck) return Object.assign({}, check);
            return Object.assign({}, prevCheck, check,
                {showCheckMessage: prevCheck.showCheckMessage});
          });
    },

    /**
     * @param {!Defs.Change} change
     * @param {!Defs.Revision} revision
     * @param {function(number, number): !Promise<!Object>} getChecks
     */
    _fetchChecks(change, revisionNumber, getChecks) {
      if (!getChecks || !change || !revisionNumber) return;

      getChecks(change._number, revisionNumber).then(checks => {
        if (revisionNumber !== this._currentPatchSet) return;
        if (checks && checks.length) {
          checks.sort((a, b) => this._orderChecks(a, b));
          if (!this._checks) {
            this._checks = checks;
          } else {
            this._checks = this._updateChecks(checks);
          }
          this.set('_status', LoadingStatus.RESULTS);
        } else {
          this._checkConfigured();
        }
      }, error => {
        this._checks = [];
        this.set('_status', LoadingStatus.EMPTY);
      });
    },

    _onVisibililityChange() {
      if (document.hidden) {
        clearInterval(this.pollChecksInterval);
        return;
      }
      this._pollChecksRegularly(this.change, this._currentPatchSet,
          this.getChecks);
    },

    _toggleCheckMessage(e) {
      const uuid = e.detail.uuid;
      if (!uuid) {
        console.warn('uuid not found');
        return;
      }
      const idx = this._checks.findIndex(check => check.checker_uuid === uuid);
      if (idx == -1) {
        console.warn('check not found');
        return;
      }
      // Update subproperty of _checks[idx] so that it reflects to polymer
      this.set(`_checks.${idx}.showCheckMessage`,
          !this._checks[idx].showCheckMessage);
    },

    _pollChecksRegularly(change, revisionNumber, getChecks) {
      if (!change || !revisionNumber || !getChecks) return;
      if (this.pollChecksInterval) {
        clearInterval(this.pollChecksInterval);
      }
      const poll = () => this._fetchChecks(change, revisionNumber, getChecks);
      poll();
      this.pollChecksInterval = setInterval(poll, CHECKS_POLL_INTERVAL_MS);
      if (!this.visibilityChangeListenerAdded) {
        this.visibilityChangeListenerAdded = true;
        this.listen(document, 'visibilitychange', '_onVisibililityChange');
      }
    },

    _checkConfigured() {
      const repository = this.change['project'];
      this.isConfigured(repository).then(configured => {
        const status =
            configured ? LoadingStatus.EMPTY : LoadingStatus.NOT_CONFIGURED;
        this.set('_status', status);
      });
    },

    _isLoading(status) {
      return status === LoadingStatus.LOADING;
    },
    _isEmpty(status) {
      return status === LoadingStatus.EMPTY;
    },
    _hasResults(status) {
      return status === LoadingStatus.RESULTS;
    },
    _isNotConfigured(status) {
      return status === LoadingStatus.NOT_CONFIGURED;
    },
  });
})();
