import { Component, Event, State, Prop, h, Watch, } from '@stencil/core';
export class TeliaToggle {
  constructor() {
    /** When set, the toggle button is disabled and the change event won't be emitted */
    this.disabled = false;
    /** The position of the label. When set to neither after nor before, the label will be hidden but still set as aria-label for the button element */
    this.labelPosition = 'before';
    /** Tracking id is used to identify and count Component usage */
    this.dataTrackingId = 'telia-toggle';
    this.dragged = false;
    this.dragging = false;
    this.dragStartX = 0;
    this.dragX = 0;
    this.eventListeners = {
      mousemove: this.onDrag.bind(this),
      touchmove: this.onDrag.bind(this),
      mouseup: this.endDragEmitChange.bind(this),
      touchend: this.endDragEmitChange.bind(this),
    };
    this.emitChange = event => {
      if (this.disabled)
        return;
      this.internalSelected = !this.internalSelected;
      this.vocaChange.emit({
        originalEvent: event,
        value: this.internalSelected,
      });
    };
  }
  setInternalSelected(newValue) {
    this.internalSelected = newValue;
  }
  componentWillLoad() {
    this.internalSelected = this.selected;
    this.remSize = 10;
    this.trackHeight = 2 * this.remSize;
    this.thumbMaxDragRange = this.trackHeight * 1.2;
    this.thumbPressedLineHeight = Math.round(0.83 * this.remSize);
    this.thumbLineWidth = 0.2 * this.remSize;
  }
  addEventListeners() {
    Object.entries(this.eventListeners).forEach(([eventName, listener]) => {
      document.addEventListener(eventName, listener);
    });
  }
  removeEventListeners() {
    Object.entries(this.eventListeners).forEach(([eventName, listener]) => {
      document.removeEventListener(eventName, listener);
    });
  }
  initDrag(event) {
    this.stopPrevent(event);
    if (!this.disabled) {
      this.addEventListeners();
      this.dragging = true;
      this.dragStartX = this.getClientX(event);
      this.dragX = this.getClientX(event);
    }
  }
  endDrag(event) {
    event && this.stopPrevent(event);
    this.removeEventListeners();
    this.dragged = false;
    this.dragging = false;
    this.dragStartX = 0;
    this.dragX = 0;
  }
  endDragEmitChange(event) {
    if (!this.dragged || this.isDraggedHalfway()) {
      this.emitChange(event);
    }
    this.endDrag(event);
  }
  onDrag(event) {
    const draggedRange = Math.abs(Math.round(this.dragX - this.dragStartX));
    this.dragged = draggedRange > 0;
    this.dragX = this.getClientX(event);
  }
  getClientX(event) {
    var _a, _b, _c;
    return (_a = event.clientX) !== null && _a !== void 0 ? _a : (_c = (_b = event.touches) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.clientX;
  }
  toggleOnEnter(event) {
    this.stopPrevent(event);
    if (event.key === 'Enter' || event.key === ' ') {
      this.emitChange(event);
    }
  }
  onLabelClick(event) {
    this.stopPrevent(event);
    if (event.type === 'click') {
      this.emitChange(event);
    }
  }
  stopPrevent(event) {
    event.cancelable && event.preventDefault();
    event.stopPropagation();
  }
  getThumbOffset() {
    const diff = Math.round(this.dragX - this.dragStartX);
    const stateOffset = this.internalSelected ? this.thumbMaxDragRange : 0;
    const offset = diff + stateOffset;
    if (offset > this.thumbMaxDragRange) {
      return this.thumbMaxDragRange;
    }
    else if (offset < 0) {
      return 0;
    }
    else {
      return offset;
    }
  }
  isDraggedHalfway() {
    return this.internalSelected
      ? this.getThumbOffset() < this.thumbMaxDragRange / 2
      : this.getThumbOffset() > this.thumbMaxDragRange / 2;
  }
  getValueByState(onValue, offValue) {
    if (this.internalSelected) {
      return this.isDraggedHalfway() ? offValue : onValue;
    }
    else {
      return this.isDraggedHalfway() ? onValue : offValue;
    }
  }
  calculateThumbPadding() {
    const halfDragRange = this.thumbMaxDragRange / 2;
    const halfwayDraggedPercentage = Math.abs((this.getThumbOffset() - halfDragRange) / halfDragRange);
    const topBottomPadding = `${(this.trackHeight -
      this.thumbPressedLineHeight * halfwayDraggedPercentage) /
      2}px`;
    const onPadding = `${topBottomPadding} ${(this.trackHeight - this.thumbLineWidth) / 2}px`;
    const offPadding = `${this.trackHeight / 2}px`;
    return this.getValueByState(onPadding, offPadding);
  }
  getThumbStyle() {
    const cursor = this.dragged ? 'grabbing' : 'inherit';
    const padding = this.calculateThumbPadding();
    const transform = `translateX(${this.getThumbOffset()}px)`;
    const transition = `all 200ms ease${this.dragged ? ', transform 0ms, padding 0ms' : ''}`;
    return this.dragging ? { cursor, padding, transform, transition } : {};
  }
  getThumbClass() {
    const thumbBaseClass = 'telia-toggle__thumb';
    const stateClass = this.getValueByState(`${thumbBaseClass}--on`, `${thumbBaseClass}--off`);
    const draggingClass = this.dragging ? ` ${thumbBaseClass}--dragging` : '';
    return `${thumbBaseClass} ${stateClass}${draggingClass}`;
  }
  getTrackClass() {
    const trackBaseClass = 'telia-toggle__track';
    const stateClass = this.getValueByState(`${trackBaseClass}--on`, `${trackBaseClass}--off`);
    return `${trackBaseClass} ${stateClass}`;
  }
  renderLabel() {
    const labelPositionClass = this.labelPosition
      ? ` telia-toggle__label--${this.labelPosition}`
      : '';
    return (this.label && (h("span", { class: `telia-toggle__label${labelPositionClass}`, onMouseUp: e => this.endDrag(e), onTouchEnd: e => this.endDragEmitChange(e), onClick: e => this.onLabelClick(e) }, this.labelPosition !== 'none' && this.label)));
  }
  render() {
    const componentClass = 'telia-toggle';
    const wrapperClasses = {
      [`${componentClass}`]: true,
      [`${componentClass}--label-${this.labelPosition}`]: true,
      [`${componentClass}--disabled`]: this.disabled,
    };
    return (h("div", { class: wrapperClasses },
      h("button", { "aria-pressed": this.internalSelected ? 'true' : 'false', disabled: this.disabled, "aria-labelledby": this.labelledby, onKeyUp: e => this.toggleOnEnter(e) },
        h("telia-visually-hidden", null, this.label)),
      (this.labelPosition === 'before' || this.labelPosition === 'none') &&
        this.renderLabel(),
      h("div", { class: this.getTrackClass(), onMouseUp: e => this.endDrag(e), onTouchEnd: e => this.endDragEmitChange(e), onClick: e => this.onLabelClick(e) },
        h("div", { style: this.getThumbStyle(), class: this.getThumbClass(), onMouseDown: e => this.initDrag(e), onTouchStart: e => this.initDrag(e), onMouseUp: e => this.endDragEmitChange(e), onTouchEnd: e => this.endDragEmitChange(e), onClick: e => this.stopPrevent(e) },
          h("div", { class: "telia-toggle__thumb-line" })),
        h("telia-vst", { dataTrackingId: this.dataTrackingId })),
      this.labelPosition === 'after' && this.renderLabel()));
  }
  static get is() { return "telia-toggle"; }
  static get encapsulation() { return "shadow"; }
  static get originalStyleUrls() { return {
    "$": ["telia-toggle.scss"]
  }; }
  static get styleUrls() { return {
    "$": ["telia-toggle.css"]
  }; }
  static get properties() { return {
    "dataTestid": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Test id set for web component host"
      },
      "attribute": "data-testid",
      "reflect": false
    },
    "selected": {
      "type": "boolean",
      "mutable": false,
      "complexType": {
        "original": "boolean",
        "resolved": "boolean",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Set the toggle selected state"
      },
      "attribute": "selected",
      "reflect": false
    },
    "disabled": {
      "type": "boolean",
      "mutable": false,
      "complexType": {
        "original": "boolean",
        "resolved": "boolean",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "When set, the toggle button is disabled and the change event won't be emitted"
      },
      "attribute": "disabled",
      "reflect": false,
      "defaultValue": "false"
    },
    "label": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": true,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "The label text"
      },
      "attribute": "label",
      "reflect": false
    },
    "labelPosition": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "'before' | 'after' | 'none'",
        "resolved": "\"after\" | \"before\" | \"none\"",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "The position of the label. When set to neither after nor before, the label will be hidden but still set as aria-label for the button element"
      },
      "attribute": "label-position",
      "reflect": false,
      "defaultValue": "'before'"
    },
    "labelledby": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Id of element that should label the toggle"
      },
      "attribute": "labelledby",
      "reflect": false
    }
  }; }
  static get states() { return {
    "dragged": {},
    "dragging": {},
    "dragStartX": {},
    "dragX": {},
    "internalSelected": {},
    "remSize": {},
    "trackHeight": {},
    "thumbMaxDragRange": {},
    "thumbPressedLineHeight": {},
    "thumbLineWidth": {},
    "eventListeners": {}
  }; }
  static get events() { return [{
      "method": "vocaChange",
      "name": "vocaChange",
      "bubbles": true,
      "cancelable": true,
      "composed": true,
      "docs": {
        "tags": [],
        "text": "The change event is emited when the toggle has been toggled successfully.\nThis event is not fired when the toggle is disabled"
      },
      "complexType": {
        "original": "TeliaToggleChangeDetail",
        "resolved": "{ originalEvent: Event; value: boolean; }",
        "references": {
          "TeliaToggleChangeDetail": {
            "location": "local"
          }
        }
      }
    }]; }
  static get watchers() { return [{
      "propName": "selected",
      "methodName": "setInternalSelected"
    }]; }
}
