import { action } from '@ember/object';
import Component from '@glimmer/component';
import deprecateSubclassing from 'ember-bootstrap/utils/deprecate-subclassing';
import { tracked } from '@glimmer/tracking';

/**
  Bootstrap-style [accordion group](http://getbootstrap.com/javascript/#collapse-example-accordion),
  with collapsible/expandable items.

  ### Usage

  Use as a block level component with any number of yielded [Components.AccordionItem](Components.AccordionItem.html)
  components as children:

  ```handlebars
  <BsAccordion as |acc|>
    <acc.item @value={{1}} @title="First item">
      <p>Lorem ipsum...</p>
      <button {{on "click" (fn acc.change 2)}}>
        Next
      </button>
    </acc.item>
    <acc.item @value={{2}} @title="Second item">
      <p>Lorem ipsum...</p>
    </acc.item>
    <acc.item @value={{3}} @title="Third item">
      <p>Lorem ipsum...</p>
    </acc.item>
  </BsAccordion>
  ```

  In the example above the first accordion item utilizes the yielded `change` action to add some custom behaviour.

  *Note that only invoking the component in a template as shown above is considered part of its public API. Extending from it (subclassing) is generally not supported, and may break at any time.*

  @class Accordion
  @namespace Components
  @extends Glimmer.Component
  @public
*/
@deprecateSubclassing
export default class Accordion extends Component {
  /**
   * The value of the currently selected accordion item. Set this to change selection programmatically.
   *
   * When the selection is changed by user interaction this property will not update by using two-way bindings in order
   * to follow DDAU best practices. If you want to react to such changes, subscribe to the `onChange` action
   *
   * @property selected
   * @public
   */

  /**
   * @property itemComponent
   * @type {String}
   * @private
   */

  @tracked
  _isSelected = this.args.selected;
  _isSelectedNonTracked = this.args.selected;

  _prevSelected = this.args.selected;

  /**
   * The value of the currently selected accordion item
   *
   * @property isSelected
   * @private
   */
  get isSelected() {
    // ideally we would have used @localCopy here, but unfortunately this fails for Ember 3.16 in this special case
    // see https://github.com/pzuraq/tracked-toolbox/issues/17
    // So don't look at this, it is going to get ugly...
    this._isSelected; // just consume this to invalidate the getter when this changes

    if (this.args.selected && this._prevSelected !== this.args.selected) {
      // eslint-disable-next-line ember/no-side-effects
      this._isSelectedNonTracked = this._prevSelected = this.args.selected;
    }

    return this._isSelectedNonTracked;
  }
  set isSelected(value) {
    this._isSelectedNonTracked = value;
    this._isSelected = value;
  }

  /**
   * Action when the selected accordion item is about to be changed.
   *
   * You can return false to prevent changing the active item, and do that in your action by
   * setting the `selected` accordingly.
   *
   * @event onChange
   * @param newValue
   * @param oldValue
   * @public
   */

  @action
  doChange(newValue) {
    let oldValue = this.isSelected;
    if (oldValue === newValue) {
      newValue = null;
    }
    if (this.args.onChange?.(newValue, oldValue) !== false) {
      this.isSelected = newValue;
    }
  }
}