/**
 * Copyright (c) HashiCorp, Inc.
 * SPDX-License-Identifier: BUSL-1.1
 */

import { inject as service } from '@ember/service';
import { computed, get, set } from '@ember/object';
import CollectionComponent from 'ember-collection/components/ember-collection';
import needsRevalidate from 'ember-collection/utils/needs-revalidate';
import Grid from 'ember-collection/layouts/grid';
import Slotted from 'block-slots';

const formatItemStyle = Grid.prototype.formatItemStyle;

export default CollectionComponent.extend(Slotted, {
  tagName: '',
  dom: service('dom'),
  width: 1150,
  rowHeight: 50,
  maxHeight: 500,
  checked: null,
  hasCaption: false,
  init: function () {
    this._super(...arguments);
    this.guid = this.dom.guid(this);
    // TODO: The row height should auto calculate properly from the CSS
    const o = this;
    this['cell-layout'] = new Grid(this.width, this.rowHeight);
    this['cell-layout'].formatItemStyle = function (itemIndex) {
      let style = formatItemStyle.apply(this, arguments);
      if (o.checked === itemIndex) {
        style = `${style};z-index: 1`;
      }
      return style;
    };
  },
  didInsertElement: function () {
    this._super(...arguments);
    this.$element = this.dom.element(`#${this.guid}`);
    this.actions.resize.apply(this, [{ target: this.dom.viewport() }]);
  },

  style: computed('rowHeight', '_items', 'maxRows', 'maxHeight', {
    get() {
      const maxRows = this.rows;
      let height = this.maxHeight;

      if (maxRows) {
        let rows = Math.max(3, get(this._items || [], 'length'));
        rows = Math.min(maxRows, rows);
        height = this.rowHeight * rows + 29;
      }

      return { height };
    },

    set(_key, value) {
      return value;
    },
  }),

  willRender: function () {
    this._super(...arguments);
    set(this, 'hasCaption', this._isRegistered('caption'));
    set(this, 'hasActions', this._isRegistered('actions'));
  },
  // `ember-collection` bug workaround
  // https://github.com/emberjs/ember-collection/issues/138
  _needsRevalidate: function () {
    if (this.isDestroyed || this.isDestroying) {
      return;
    }
    if (this._isGlimmer2()) {
      this.rerender();
    } else {
      needsRevalidate(this);
    }
  },
  actions: {
    resize: function (e) {
      const $tbody = this.$element;
      const $appContent = this.dom.element('.app-view');
      if ($appContent) {
        const border = 1;
        const rect = $tbody.getBoundingClientRect();
        const space = rect.top + border;
        const height = e.target.innerHeight - space;
        this.set('maxHeight', Math.max(0, height));
        // TODO: The row height should auto calculate properly from the CSS
        this['cell-layout'] = new Grid($appContent.clientWidth, this.rowHeight);
        const o = this;
        this['cell-layout'].formatItemStyle = function (itemIndex) {
          let style = formatItemStyle.apply(this, arguments);
          if (o.checked === itemIndex) {
            style = `${style};z-index: 1`;
          }
          return style;
        };
        this.updateItems();
        this.updateScrollPosition();
      }
    },
    click: function (e) {
      return this.dom.clickFirstAnchor(e);
    },
    change: function (index, e = {}) {
      if (this.$tr) {
        this.$tr.style.zIndex = null;
      }
      if (e.target && e.target.checked && index !== this.checked) {
        set(this, 'checked', parseInt(index));
        const target = e.target;
        const $tr = this.dom.closest('tr', target);
        const $group = this.dom.sibling(target, 'div');
        const groupRect = $group.getBoundingClientRect();
        const groupBottom = groupRect.top + $group.clientHeight;

        const $footer = this.dom.element('#contentinfo');
        const footerRect = $footer.getBoundingClientRect();
        const footerTop = footerRect.top;

        if (groupBottom > footerTop) {
          $group.classList.add('above');
        } else {
          $group.classList.remove('above');
        }
        $tr.style.zIndex = 1;
        this.$tr = $tr;
      } else {
        set(this, 'checked', null);
      }
    },
  },
});
