import { injectStyle } from '@descope-ui/common/components-helpers';
import {
  createStyleMixin,
  draggableMixin,
  createProxy,
  proxyInputMixin,
  componentNameValidationMixin,
  inputOverrideValidConstraintsMixin,
} from '../../mixins';
import { componentName as descopeInternalComponentName } from './descope-passcode-internal/PasscodeInternal';
import { TextFieldClass } from '../descope-text-field/TextFieldClass';
import { LoaderRadialClass } from '../descope-loader-radial/LoaderRadialClass';
import { compose } from '../../helpers';
import { forwardAttrs, getComponentName } from '../../helpers/componentHelpers';
import {
  resetInputCursor,
  resetInputLabelPosition,
  resetInputFieldDefaultWidth,
} from '../../helpers/themeHelpers/resetHelpers';

export const componentName = getComponentName('passcode');

const observedAttributes = ['digits'];

const customMixin = (superclass) =>
  class PasscodeMixinClass extends superclass {
    static get observedAttributes() {
      return observedAttributes.concat(superclass.observedAttributes || []);
    }

    get digits() {
      return Number.parseInt(this.getAttribute('digits'), 10) || 6;
    }

    init() {
      super.init?.();

      injectStyle(
        `
        .wrapper {
          display: flex;
          width: 100%;
          justify-content: space-between;
          direction: ltr;
          position: relative;
        }

        descope-text-field {
          direction: ltr;
        }

        .loader-container {
          display: none;
          position: absolute;
          top: 50%;
          left: 50%;
          transform: translate(-50%, -50%);
        }
          `,
        this
      );

      const template = document.createElement('template');

      template.innerHTML = `
      <${descopeInternalComponentName}
        bordered="true"
        name="code"
        tabindex="-1"
        slot="input"
        role="textbox"
      ><slot></slot></${descopeInternalComponentName}>
      `;

      this.baseElement.appendChild(template.content.cloneNode(true));

      this.inputElement = this.shadowRoot.querySelector(descopeInternalComponentName);

      forwardAttrs(this, this.inputElement, {
        includeAttrs: ['digits', 'size', 'loading', 'disabled'],
      });
    }

    attributeChangedCallback(attrName, oldValue, newValue) {
      super.attributeChangedCallback?.(attrName, oldValue, newValue);

      if (attrName === 'digits') {
        this.style['--passcode-digits-count'] = newValue;
      }
    }
  };

const {
  host,
  digitField,
  label,
  requiredIndicator,
  internalWrapper,
  focusedDigitField,
  errorMessage,
} = {
  host: { selector: () => ':host' },
  focusedDigitField: { selector: () => `${TextFieldClass.componentName}[focused="true"]` },
  digitField: { selector: () => TextFieldClass.componentName },
  label: { selector: '::part(label)' },
  requiredIndicator: { selector: '[required]::part(required-indicator)::after' },
  internalWrapper: { selector: 'descope-passcode-internal .wrapper' },
  errorMessage: { selector: '::part(error-message)' },
};

const textVars = TextFieldClass.cssVarList;
const loaderVars = LoaderRadialClass.cssVarList;

export const PasscodeClass = compose(
  createStyleMixin({
    mappings: {
      fontSize: [{ ...digitField, property: textVars.fontSize }, host],
      hostWidth: { property: 'width' },
      hostDirection: { ...host, property: 'direction' },
      fontFamily: [host, { ...label }],
      labelFontWeight: { ...label, property: 'font-weight' },
      errorMessageFontWeight: { ...errorMessage, property: 'font-weight' },
      digitValueFontWeight: {
        selector: TextFieldClass.componentName,
        property: textVars.inputValueFontWeight,
      },
      labelTextColor: [
        { ...label, property: 'color' },
        { ...label, property: '-webkit-text-fill-color' },
        { ...requiredIndicator, property: 'color' },
        { ...requiredIndicator, property: '-webkit-text-fill-color' },
      ],
      labelRequiredIndicator: { ...requiredIndicator, property: 'content' },
      errorMessageTextColor: { ...errorMessage, property: 'color' },
      errorMessageIcon: { ...errorMessage, property: 'background-image' },
      errorMessageIconSize: { ...errorMessage, property: 'background-size' },
      errorMessageIconPadding: { ...errorMessage, property: 'padding-inline-start' },
      errorMessageIconRepeat: { ...errorMessage, property: 'background-repeat' },
      errorMessageIconPosition: { ...errorMessage, property: 'background-position' },
      errorMessageFontSize: { ...errorMessage, property: 'font-size' },
      digitValueTextColor: {
        selector: TextFieldClass.componentName,
        property: textVars.inputValueTextColor,
      },
      digitSize: [
        { ...digitField, property: 'height' },
        { ...digitField, property: 'width' },
      ],
      digitPadding: { ...digitField, property: textVars.inputHorizontalPadding },
      digitTextAlign: { ...digitField, property: textVars.inputTextAlign },
      digitCaretTextColor: { ...digitField, property: textVars.inputCaretTextColor },
      digitSpacing: { ...internalWrapper, property: 'gap' },
      digitOutlineColor: { ...digitField, property: textVars.inputOutlineColor },
      digitOutlineWidth: { ...digitField, property: textVars.inputOutlineWidth },

      focusedDigitFieldOutlineColor: { ...focusedDigitField, property: textVars.inputOutlineColor },
      overlayOpacity: { ...internalWrapper, property: 'opacity' },
      spinnerSize: { selector: LoaderRadialClass.componentName, property: loaderVars.spinnerSize },
    },
  }),
  draggableMixin,
  inputOverrideValidConstraintsMixin,
  proxyInputMixin({ proxyProps: ['value', 'selectionStart'] }),
  componentNameValidationMixin,
  customMixin
)(
  createProxy({
    slots: [],
    wrappedEleName: 'vaadin-text-field',
    style: () => `
			:host {
				display: inline-flex;
				max-width: 100%;
				min-width: calc(var(--passcode-digits-count) * 2em);
			}
			${resetInputFieldDefaultWidth()}
			:host::after {
				background-color: transparent;
			}
			:host::part(input-field)::after {
				background-color: transparent;
			}

      :host([loading="true"]) descope-passcode-internal .loader-container {
        display: block;
      }

			descope-passcode-internal {
				-webkit-mask-image: none;
				padding: 0;
				width: 100%;
				height: 100%;
				min-height: initial;
			}

			descope-passcode-internal .wrapper {
				box-sizing: border-box;
				min-height: initial;
				height: 100%;
				justify-content: space-between;
			}

			descope-passcode-internal descope-text-field {
				min-width: 2em;
				max-width: var(${textVars.inputHeight});
			}

			vaadin-text-field::part(input-field) {
				background-color: transparent;
				padding: 0;
				overflow: hidden;
				-webkit-mask-image: none;
			}

      /* safari */
			vaadin-text-field::part(input-field)::after {
        opacity: 0;
      }

			vaadin-text-field {
				margin: 0;
				padding: 0;
				width: 100%;
			}

			vaadin-text-field::before {
				height: 0;
			}

			vaadin-text-field[readonly] > input:placeholder-shown {
				opacity: 1;
			}

			vaadin-text-field[readonly]::part(input-field)::after {
				border: 0 solid;
			}

			vaadin-text-field::part(input-field) {
				box-shadow: none;
			}

      ${resetInputLabelPosition('vaadin-text-field')}
			${resetInputCursor('vaadin-text-field')}
    	`,
    excludeAttrsSync: ['tabindex', 'style'],
    componentName,
  })
);

export default PasscodeClass;
