(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',
    _legacyUndefinedCheck: true,

    properties: {
      revision: Object,
      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
      },
    },

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

    attached() {
      this.pluginRestApi = this.plugin.restApi();
      this._initCreateCheckerCapability();
    },

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

    _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) {
        let indexA = StatusPriorityOrder.indexOf(a.state);
        let 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);
        }
      )
    },

    /**
     * @param {!Defs.Change} change
     * @param {!Defs.Revision} revision
     * @param {function(number, number): !Promise<!Object>} getChecks
     */
    _fetchChecks(change, revision, getChecks) {
      getChecks(change._number, revision._number).then(checks => {
        if (checks && checks.length) {
          checks.sort(this._orderChecks);
          if (!this._checks) {
            this._checks = checks;
          } else {
            // Merge checks & this_checks to keep showCheckMessage property
            this._checks = checks.map(
              (check) => {
                const prevCheck = this._checks.find(
                  (c) => { return c.checker_uuid === check.checker_uuid }
                )
                if (!prevCheck) return check;
                return Object.assign({}, check, prevCheck)
              }
            )
          }
          this.set('_status', LoadingStatus.RESULTS);
        } else {
          this._checkConfigured();
        }
      });
    },

    _onVisibililityChange() {
      if (document.hidden) {
        clearInterval(this.pollChecksInterval);
        return;
      }
      this._pollChecksRegularly(this.change, this.revision, 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, revision, getChecks) {
      if (this.pollChecksInterval) {
        clearInterval(this.pollChecksInterval);
      }
      const poll = () => this._fetchChecks(change, revision, 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;
    },
  });
})();
