import { TextClass } from '@descope-ui/descope-text/class';
import { injectStyle } from '@descope-ui/common/components-helpers';
import { createBaseClass } from '../../baseClasses/createBaseClass';
import { compose } from '../../helpers';
import { getComponentName, observeAttributes } from '../../helpers/componentHelpers';
import { componentNameValidationMixin, createStyleMixin, draggableMixin } from '../../mixins';
import { TextFieldClass } from '../descope-text-field/TextFieldClass';

export const componentName = getComponentName('security-questions-verify');

const textFieldsAttrs = [
  'full-width',
  'readonly',
  'size',
  'answer-placeholder',
  'answer-data-errormessage-value-missing',
  'st-error-message-icon',
  'st-error-message-icon-size',
  'st-error-message-icon-padding',
];

const textsAttrs = ['question-mode'];

const attrMappings = {
  'answer-placeholder': 'placeholder',
  'answer-data-errormessage-value-missing': 'data-errormessage-value-missing',
  'question-mode': 'mode',
};

const attrsToSync = [...textFieldsAttrs, ...textsAttrs];

const attrsToReRender = ['questions'];
class RawSecurityQuestionsVerify extends createBaseClass({ componentName, baseSelector: 'div' }) {
  constructor() {
    super();

    this.attachShadow({ mode: 'open' }).innerHTML = `
    <div></div>
		`;

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

      div {
        display: flex;
        flex-direction: column;
      }
        `,
      this
    );
  }

  #renderQuestions() {
    const res = this.questions.map(
      ({ id, text }) =>
        // <!--html-->
        `
      <div class="question-wrapper">
      <descope-text
        data-id="${id}"
      >${text}</descope-text>

      <descope-text-field
        data-id="${id}"
        required="true"
        bordered="true"
      ></descope-text-field>
    </div>
      `
      // <!--!html-->
    );

    this.baseElement.innerHTML = res.join(
      '<spacer></spacer><descope-divider></descope-divider><spacer></spacer>'
    );

    this.#syncAttrs(attrsToSync);

    // focus input when text is clicked
    this.texts.forEach((el) => {
      const input = this.textFields.find(
        (field) => field.getAttribute('data-id') === el.getAttribute('data-id')
      );

      if (input) el.onclick = input.focus.bind(input);
    });
  }

  reportValidity() {
    this.textFields.reverse().forEach((el) => el.reportValidity());

    return this.checkValidity();
  }

  checkValidity() {
    return this.textFields.every((el) => el.checkValidity());
  }

  get questions() {
    try {
      return JSON.parse(this.getAttribute('questions')) || [];
    } catch (e) {
      // eslint-disable-next-line no-console
      console.error(componentName, 'Error parsing questions attribute', e);
      return [];
    }
  }

  get texts() {
    return Array.from(this.baseElement.querySelectorAll('descope-text'));
  }

  get textFields() {
    return Array.from(this.baseElement.querySelectorAll('descope-text-field'));
  }

  get elements() {
    return Array.from(this.baseElement.querySelectorAll('descope-text, descope-text-field'));
  }

  get value() {
    return this.textFields.map((el) => ({ id: el.getAttribute('data-id'), answer: el.value }));
  }

  set value(val = []) {
    val.forEach(({ id, answer }) => {
      const textField = this.textFields.find((el) => el.getAttribute('data-id') === id);
      if (textField) textField.value = answer;
    });
  }

  #updateAttribute(ele, attrName, value) {
    if (value === null) ele.removeAttribute(attrName);
    else ele.setAttribute(attrName, value);
  }

  #getElementsToUpdate(attr) {
    switch (true) {
      case textFieldsAttrs.includes(attr):
        return this.textFields;
      case textsAttrs.includes(attr):
        return this.texts;
      default:
        return [];
    }
  }

  #syncAttrs(attrs) {
    attrs.forEach((attr) => {
      this.#getElementsToUpdate(attr).forEach((el) => {
        this.#updateAttribute(el, attrMappings[attr] || attr, this.getAttribute(attr));
      });
    });
  }

  init() {
    super.init?.();
    // render new components
    observeAttributes(
      this,
      () => {
        this.#renderQuestions();
      },
      { includeAttrs: attrsToReRender }
    );

    // update existing components
    observeAttributes(this, this.#syncAttrs.bind(this), {
      includeAttrs: attrsToSync,
    });
  }
}

export const SecurityQuestionsVerifyClass = compose(
  createStyleMixin({ componentNameOverride: getComponentName('input-wrapper') }),
  createStyleMixin({
    mappings: {
      hostWidth: [{ selector: () => ':host', property: 'width' }, { property: 'width' }],
      hostDirection: [
        { selector: () => ':host', property: 'direction' },
        {
          selector: () => TextClass.componentName,
          property: TextClass.cssVarList.hostDirection,
        },
        {
          selector: () => TextFieldClass.componentName,
          property: TextFieldClass.cssVarList.hostDirection,
        },
      ],
      gap: { selector: () => 'div', property: 'gap' },
      questionTextAlign: {
        selector: () => TextClass.componentName,
        property: TextClass.cssVarList.textAlign,
      },
      questionFontSize: {
        selector: () => TextClass.componentName,
        property: TextClass.cssVarList.fontSize,
      },
      questionFontFamily: {
        selector: () => TextClass.componentName,
        property: TextClass.cssVarList.fontFamily,
      },
      questionCursor: {
        selector: () => TextClass.componentName,
        property: 'cursor',
      },

      errorMessageIcon: {
        selector: () => TextClass.componentName,
        property: TextClass.cssVarList.errorMessageIcon,
      },
      errorMessageIconSize: {
        selector: () => TextClass.componentName,
        property: TextClass.cssVarList.errorMessageSize,
      },
      errorMessageIconPadding: {
        selector: () => TextClass.componentName,
        property: TextClass.cssVarList.errorMessagePadding,
      },
      errorMessageIconRepeat: {
        selector: () => TextClass.componentName,
        property: TextClass.cssVarList.errorMessageRepeat,
      },
      errorMessageIconPosition: {
        selector: () => TextClass.componentName,
        property: TextClass.cssVarList.errorMessagePosition,
      },
      errorMessageFontSize: {
        selector: () => TextClass.componentName,
        property: TextClass.cssVarList.errorMessageFontSize,
      },
    },
  }),
  draggableMixin,
  componentNameValidationMixin
)(RawSecurityQuestionsVerify);
