import { TextClass } from '@descope-ui/descope-text/class';
import { ButtonClass } from '@descope-ui/descope-button/class';
import { IconClass } from '@descope-ui/descope-icon/class';
import { BadgeClass } from '@descope-ui/descope-badge/class';
import { injectStyle } from '@descope-ui/common/components-helpers';
import { createStyleMixin, draggableMixin, componentNameValidationMixin } from '../../mixins';
import { createBaseClass } from '../../baseClasses/createBaseClass';
import { compose } from '../../helpers';
import { getComponentName } from '../../helpers/componentHelpers';
import greenVIcon from './green-v.svg';

export const componentName = getComponentName('user-auth-method');
class RawUserAuthMethod extends createBaseClass({
  componentName,
  baseSelector: ':host > .root',
}) {
  constructor() {
    super();

    this.attachShadow({ mode: 'open' }).innerHTML = `
      <div class="root">
        <div class="text-wrapper">
          <slot name="method-icon"></slot>
          <descope-text st-text-align="auto" data-id="label-text" variant="body1" mode="primary"></descope-text>
        </div>

        <div class="btn-wrapper">
          <descope-button class="btn unfulfilled hidden" size="sm" variant="link" mode="primary">
            <slot name="button-icon"></slot>
          </descope-button>
          <descope-button class="btn fulfilled hidden" size="sm" variant="link" mode="primary">
            <slot name="fulfilled-button-icon"></slot>
          </descope-button>
          <div class="status-indicator hidden">
            <vaadin-icon src=${greenVIcon}></vaadin-icon>
          </div>
          <descope-button class="hidden-btn" size="sm" variant="link" mode="primary"></descope-button>
        </div>
      </div>
		`;

    injectStyle(
      `
      :host {
					display: inline-flex;
				}

        vaadin-icon {
          color: currentcolor;
        }

        .root {
          display: flex;
          width: 100%;
          height: 100%;
          align-items: center;
        }

        .btn-wrapper {
          display: flex;
          justify-content: space-between;
          align-items: center;
          flex-grow: 0;
        }

        .text-wrapper {
          display: flex;
          align-items: center;
          flex-grow: 1;
          min-width: 0;
        }

        descope-text::part(text-wrapper) {
          text-overflow: ellipsis;
          overflow: hidden;
          white-space: nowrap;
          width: initial;
        }

        descope-text {
          display: inline-flex;
          min-width: 0;
        }

        .status-indicator {
          width: 1em;
          height: 1em;
          display: flex;
          align-items: center;
          padding-inline-end: 1em;
        }

        .hidden {
          display: none;
        }

        .hidden-btn {
          width: 0;
          overflow: hidden;
          opacity: 0;
          pointer-events: none;
        }

        slot[name="method-icon"]:not(:empty) {
          display: inline-flex;
          align-items: center;
        }
          `,
      this
    );

    this.unfulfilledButton = this.shadowRoot.querySelector('.btn.unfulfilled');
    this.fulfilledButton = this.shadowRoot.querySelector('.btn.fulfilled');
    this.statusIndicator = this.shadowRoot.querySelector('.status-indicator');
    this.labelText = this.shadowRoot.querySelector('descope-text[data-id="label-text"]');
  }

  onLabelChange() {
    this.labelText.innerText = this.label;
    this.labelText.setAttribute('title', this.label);
  }

  updateButtonLabel(btnRef, label) {
    let textSpanEle = btnRef.querySelector('span');

    if (label) {
      if (!textSpanEle) {
        textSpanEle = document.createElement('span');
        btnRef.appendChild(textSpanEle);
      }
      textSpanEle.innerText = label;
    } else if (textSpanEle) {
      btnRef.removeChild(textSpanEle);
    }
  }

  onFulfilledChange() {
    if (this.isFulfilled) {
      this.unfulfilledButton.classList.add('hidden');
      this.handleFulfilled();
    } else {
      this.fulfilledButton.classList.add('hidden');
      this.handleUnfulfilled();
    }
  }

  handleFulfilled() {
    this.fulfilledButton.classList.toggle('hidden', !this.isFulfilledEditable);
    this.statusIndicator.classList.toggle('hidden', this.isFulfilledEditable);
  }

  handleUnfulfilled() {
    this.unfulfilledButton.classList.toggle('hidden', !this.isUnfulfilledEditable);
    this.statusIndicator.classList.toggle('hidden', this.isUnfulfilledEditable);
  }

  get label() {
    return this.getAttribute('label') || '';
  }

  get unfulfilledButtonLabel() {
    return this.getAttribute('button-label') || '';
  }

  get fulfilledButtonLabel() {
    return this.getAttribute('fulfilled-button-label') || '';
  }

  get isFulfilled() {
    return this.getAttribute('fulfilled') === 'true';
  }

  get isFulfilledEditable() {
    return this.getAttribute('fulfilled-editable') === 'true';
  }

  get isUnfulfilledEditable() {
    // this is to keep backward compatibility with previous versions
    return this.getAttribute('unfulfilled-editable') !== 'false';
  }

  init() {
    this.onLabelChange();
    this.updateButtonLabel(this.fulfilledButton, this.fulfilledButtonLabel);
    this.updateButtonLabel(this.unfulfilledButton, this.unfulfilledButtonLabel);
    this.onFulfilledChange();

    this.unfulfilledButton.addEventListener('click', () =>
      this.dispatchEvent(new CustomEvent('button-clicked', { bubbles: true, composed: true }))
    );

    this.fulfilledButton.addEventListener('click', () => {
      this.dispatchEvent(
        new CustomEvent('fulfilled-button-clicked', { bubbles: true, composed: true })
      );
    });
  }

  static get observedAttributes() {
    return [
      'label',
      'fulfilled',
      'button-label',
      'fulfilled-button-label',
      'fulfilled-editable',
      'unfulfilled-editable',
    ].concat(super.observedAttributes);
  }

  attributeChangedCallback(name, oldValue, newValue) {
    super.attributeChangedCallback?.(name, oldValue, newValue);
    if (oldValue === newValue) {
      return;
    }

    if (name === 'label') {
      this.onLabelChange();
    } else if (name === 'fulfilled') {
      this.onFulfilledChange();
    } else if (name === 'button-label') {
      this.updateButtonLabel(this.unfulfilledButton, this.unfulfilledButtonLabel);
    } else if (name === 'fulfilled-button-label') {
      this.updateButtonLabel(this.fulfilledButton, this.fulfilledButtonLabel);
    } else if (name === 'fulfilled-editable' && this.isFulfilled) {
      this.handleFulfilled();
    } else if (name === 'unfulfilled-editable' && !this.isFulfilled) {
      this.handleUnfulfilled();
    }
  }
}

const { host, textField, buttons, badge, textWrapper, methodIconSlot } = {
  host: { selector: () => ':host' },
  textField: { selector: 'descope-text' },
  buttons: { selector: 'descope-button' },
  badge: { selector: 'descope-badge' },
  textWrapper: { selector: ' .text-wrapper' },
  methodIconSlot: { selector: 'slot[name="method-icon"]:not(:empty)' },
};

export const UserAuthMethodClass = compose(
  createStyleMixin({
    mappings: {
      hostWidth: { ...host, property: 'width' },
      hostMinWidth: { ...host, property: 'min-width' },
      hostMaxWidth: { ...host, property: 'max-width' },
      hostDirection: [
        { ...host, property: 'direction' },
        { ...textField, property: TextClass.cssVarList.hostDirection },
        { ...buttons, property: ButtonClass.cssVarList.hostDirection },
        { ...badge, property: BadgeClass.cssVarList.hostDirection },
      ],
      itemsGap: [{ property: 'gap' }, { ...textWrapper, property: 'gap' }],
      iconSize: [
        { ...methodIconSlot, property: 'width' },
        { ...methodIconSlot, property: 'height' },
      ],
      iconColor: [{ selector: () => '::slotted(*)', property: IconClass.cssVarList.fill }],
    },
  }),
  draggableMixin,
  componentNameValidationMixin
)(RawUserAuthMethod);
