import { Component, h, Listen, Prop, State, Watch, Event, Element } from '@stencil/core';
import { getTranslations, translate, TRANSLATIONS } from '../../utils/locale.utils';
import '@everymatrix/general-input';
export class GeneralRegistration {
  constructor() {
    /**
    * Currently selected language
    */
    this.language = 'en';
    /**
     * Client custom styling via inline styles
     */
    this.clientStyling = '';
    /**
     * Client custom styling via url
     */
    this.clientStylingUrl = '';
    /**
     * Translations via URL
     */
    this.translationUrl = '';
    /**
     * Affiliate code to be passed in and sent in the registration.
     */
    this.btag = null;
    this.isLoading = true;
    this.forms = [];
    this.limitStylingAppends = false;
    this.autofilled = false;
    this.listOfInputValues = [];
    this.listOfInputValidity = [];
    this.listOfActions = [];
    this.listOfInputs = [];
    this.emitValue = false;
    this.backButtonPressed = false;
    this.registerErrors = false;
    this.registrationStepsState = {
      regId: null
    };
    this.setClientStyling = () => {
      let sheet = document.createElement('style');
      sheet.innerHTML = this.clientStyling;
      this.host.shadowRoot.prepend(sheet);
    };
    this.setClientStylingURL = () => {
      let url = new URL(this.clientStylingUrl);
      let cssFile = document.createElement('style');
      fetch(url.href)
        .then((res) => res.text())
        .then((data) => {
        cssFile.innerHTML = data;
        this.clientStyling = data;
        setTimeout(() => { this.host.shadowRoot.prepend(cssFile); }, 1);
      });
    };
  }
  sendStep() {
    this.registrationStepUpdated.emit(this.registrationStep);
    window.postMessage({ type: 'registrationStepUpdated', step: this.registrationStep }, window.location.href);
  }
  setFormValidity() {
    this.errorMessage = '';
    if (this.listOfInputValidity) {
      this.isFormValid = !this.getInvalidStatus(this.listOfInputValidity);
    }
    //Check for autofilled.
    if (this.listOfInputs.some(inputs => inputs.autofill)) {
      this.autofilled = true;
    }
  }
  addBtag() {
    this.addBtagValue();
  }
  checkInputsValidityHandler(event) {
    // Set isValid state of the input in the list.
    this.listOfInputValidity.find(input => input.name == event.detail.name).isValid = event.detail.valid;
    // Check if any one is invalid.
    this.isFormValid = !this.getInvalidStatus(this.listOfInputValidity);
  }
  getInputsValueHandler(event) {
    this.listOfInputValues.find(input => {
      if (input.name == event.detail.name) {
        input.value = event.detail.value;
        input.type = event.detail.type || null;
      }
    });
    this.stepsStateMachine({ event: 'set', type: 'values' });
  }
  componentWillLoad() {
    return this.getRegisterConfig()
      .then((config) => {
      this.formatConfig(config);
      this.isFormValid = !this.getInvalidStatus(this.listOfInputValidity);
      this.stepsStateMachine({ event: 'set', type: 'inputs' });
    });
  }
  componentDidLoad() {
    this.registrationWidgetLoaded.emit();
    window.postMessage({ type: 'registrationWidgetLoaded' }, window.location.href);
    if (!this.limitStylingAppends && this.host) {
      if (this.clientStyling)
        this.setClientStyling();
      if (this.clientStylingUrl)
        this.setClientStylingURL();
      this.limitStylingAppends = true;
    }
  }
  nextHandler(e) {
    e.preventDefault();
    // Trigger events in subwidgets.
    this.emitValue = true;
    this.setRegisterStep();
  }
  backHandler(e) {
    e.preventDefault();
    this.registrationStep = this.stepChange('decrement');
    this.stepsStateMachine({ event: 'get', type: 'inputs' });
    this.stepsStateMachine({ event: 'get', type: 'values' });
  }
  stepsStateMachine(state) {
    switch (state.event) {
      case 'set':
        if (state.type == 'inputs') {
          this.registrationStepsState[this.registrationStep].fields = this.listOfInputs;
          this.registrationStepsState[this.registrationStep].actions = this.listOfActions;
          this.registrationStepsState[this.registrationStep].fieldsValidity = this.listOfInputValidity;
        }
        if (state.type == 'values') {
          this.registrationStepsState[this.registrationStep].registerUserData = this.listOfInputValues.reduce((acc, curr) => {
            acc[curr.name] = { value: curr.value, isDuplicate: curr.isDuplicate };
            return acc;
          }, {});
        }
        localStorage.setItem('registrationStepsState', JSON.stringify(this.registrationStepsState));
        break;
      case 'get':
        const savedUserData = JSON.parse(localStorage.getItem('registrationStepsState'));
        if (!savedUserData)
          return;
        if (state.type == 'inputs') {
          this.listOfInputs = this.registrationStepsState[this.registrationStep].fields;
          this.listOfActions = this.registrationStepsState[this.registrationStep].actions;
          this.listOfInputValidity = this.registrationStepsState[this.registrationStep].fieldsValidity;
        }
        if (state.type == 'values') {
          const savedValues = savedUserData[this.registrationStep].registerUserData;
          this.listOfInputValues = Object.keys(savedValues).map(name => {
            return { name, value: savedValues[name].value, isDuplicate: savedValues[name].isDuplicate };
          });
          // Give to each field the user input as the default value.
          this.listOfInputValues.forEach(inputValue => {
            const input = this.listOfInputs.find(input => input.name === inputValue.name);
            if (input) {
              input.defaultValue = inputValue.value;
            }
          });
        }
        this.isFormValid = !this.getInvalidStatus(this.listOfInputValidity);
        break;
    }
  }
  getRegisterConfig(registrationID) {
    const url = new URL(`${this.endpoint}/v1/player/legislation/registration/config`);
    const headers = new Headers();
    headers.append('Content-Type', 'application/json');
    headers.append('Accept', 'application/json');
    if (registrationID) {
      url.searchParams.append('registrationId', registrationID);
    }
    const options = {
      method: 'GET',
      headers
    };
    return new Promise((resolve, reject) => {
      this.isLoading = true;
      fetch(url.href, options)
        .then((res) => res.json())
        .then((config) => {
        this.isLoading = false;
        resolve(config);
      }).catch((err) => {
        this.isLoading = false;
        console.error(err);
        reject(err);
      }).finally(() => {
        this.isLoading = false;
      });
    });
  }
  setRegisterStep() {
    this.isLoadingPOST = true;
    const url = new URL(`${this.endpoint}/v1/player/legislation/registration/step`);
    const registerStep = {
      registrationId: this.registrationID,
      registerUserDto: this.listOfInputValues
        .filter(input => !input.isDuplicate)
        .reduce((acc, curr) => {
        // Because the API is very robust, some values need to be split as separate entities.  
        if (curr.name === 'TypeOfPublicArea') {
          acc[curr.name] = curr.value.toLowerCase();
        }
        else if (curr.type === 'tel') {
          //@ts-ignore
          acc['MobilePrefix'] = curr.value.prefix;
          //@ts-ignore
          acc[curr.name] = curr.value.phone;
        }
        else if (curr.type === 'checkboxgroup') {
          // Skip adding the parent of the checkboxgroup as a key. 
          if (curr.value !== null) {
            Object.entries(curr.value).forEach(([key, value]) => {
              acc[key] = value ? 'true' : 'false';
            });
          }
        }
        else {
          acc[curr.name] = curr.value;
        }
        return acc;
      }, {}),
      step: this.registrationStep,
    };
    const headers = new Headers();
    headers.append('Content-Type', 'application/json');
    headers.append('Accept', 'application/json');
    const options = {
      method: 'POST',
      body: JSON.stringify(registerStep),
      headers
    };
    fetch(url.href, options)
      .then((res) => {
      if (!res.ok) {
        return res.json().then(error => {
          this.errorCode = error.thirdPartyResponse.errorCode;
          // Show the idomsoft error if it is the case
          if (this.errorCode == 'GmErr_BadRequest_IdomsoftVerification_ShouldRetry') {
            this.errorMessage = error.thirdPartyResponse.message;
          }
          else if (this.errorCode === 'GmErr_Forbidden_UserAccount_NavExcluded') {
            this.errorMessage = translate(`${this.errorCode}`, this.language);
          }
          else if (this.errorCode == 'GmErr_BadRequest') {
            this.errorMessage = error.thirdPartyResponse.message;
          }
          else {
            this.errorMessage = translate(`${this.errorCode}`, this.language) || translate(`generalError`, this.language);
          }
        });
      }
      return res.json();
    })
      .then((data) => {
      this.isLoadingPOST = false;
      this.registrationID = data.registrationId;
      if (this.listOfActions.some(action => action == '/register')) {
        this.setRegister();
      }
      else {
        // After sending the current step, increment and check if the next one is in state.
        this.registrationStep = this.stepChange('increment');
        // If step is present in state do NOT fetch the next config.
        if (Object.keys(this.registrationStepsState).find(key => key == this.registrationStep)) {
          // Use the one from state
          this.stepsStateMachine({ event: 'get', type: 'inputs' });
          this.stepsStateMachine({ event: 'get', type: 'values' });
        }
        else {
          this.getRegisterConfig(this.registrationID).then((config) => {
            // Format the new step config.
            this.formatConfig(config);
            // Set it in local storage.
            this.stepsStateMachine({ event: 'set', type: 'inputs' });
          });
        }
      }
    })
      .catch((err) => {
      this.isLoadingPOST = false;
      console.error(err);
    }).finally(() => {
      this.isLoadingPOST = false;
    });
  }
  setRegister() {
    this.isLoading = true;
    this.registerErrors = false;
    const url = new URL(`${this.endpoint}/v1/player/legislation/register`);
    const headers = new Headers();
    headers.append('Content-Type', 'application/json');
    headers.append('Accept', 'application/json');
    const options = {
      method: 'PUT',
      body: JSON.stringify({ registrationId: this.registrationID }),
      headers
    };
    fetch(url.href, options)
      .then((res) => {
      if (!res.ok) {
        this.registerErrors = true;
        return res.json().then(error => {
          this.errorCode = error.thirdPartyResponse.errorCode;
          // Show the idomsoft error if it is the case
          if (this.errorCode == 'GmErr_BadRequest_IdomsoftVerification_ShouldRetry') {
            this.errorMessage = error.thirdPartyResponse.message;
          }
          else if (this.errorCode == 'GmErr_BadRequest') {
            this.errorMessage = error.thirdPartyResponse.message;
          }
          else {
            this.errorMessage = translate(`${this.errorCode}`, this.language) || translate(`generalError`, this.language);
          }
          window.postMessage({ type: 'registrationFailed', errorMessage: error === null || error === void 0 ? void 0 : error.thirdPartyResponse.message }, window.location.href);
          window.postMessage({ type: 'WidgetNotification', data: {
              type: 'error',
              message: this.errorMessage
            } }, window.location.href);
        });
      }
      return res.json();
    })
      .then((data) => {
      this.isLoading = false;
      if (!this.registerErrors) {
        window.postMessage({ type: 'registrationSuccessful', userId: data === null || data === void 0 ? void 0 : data.userId }, window.location.href);
        window.postMessage({ type: 'WidgetNotification', data: {
            type: 'success',
            message: translate('successMessage', this.language)
          } }, window.location.href);
      }
    })
      .catch((err) => {
      this.isLoading = false;
      console.error(err);
    })
      .finally(() => {
      this.isLoading = false;
    });
  }
  formatConfig(config) {
    // Populate the list of inputs
    this.listOfInputs = config.content.fields.flatMap((field) => {
      // Special case for inputs that need to be duplicated.
      const duplicateInputRule = field.validate.custom.find(customRule => customRule.rule === 'duplicate-input');
      const inputElement = Object.assign({}, field);
      if (duplicateInputRule) {
        const duplicateInput = Object.assign(Object.assign({}, field), { name: `${field.name}Duplicate`, displayName: duplicateInputRule.displayName, isDuplicateInput: true });
        return [inputElement, duplicateInput];
      }
      else {
        return [inputElement];
      }
    });
    this.listOfInputValidity = this.listOfInputs.reduce((acc, field) => {
      var _a;
      // If the field is a togglecheckbox, add its subfields
      if (((_a = field.inputType) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === "togglecheckbox") {
        field.data.subFields.forEach(subfield => {
          acc.push({
            name: subfield.name,
            isValid: this.setInitialValidStatus(subfield)
          });
        });
      }
      else {
        acc.push({
          name: field.name,
          isValid: this.setInitialValidStatus(field)
        });
      }
      return acc;
    }, []);
    this.listOfInputValues = this.listOfInputs.reduce((acc, field) => {
      var _a, _b, _c;
      // If the field type is a 'togglecheckbox', add its subfields
      if (((_a = field.inputType) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === "togglecheckbox") {
        field.data.subFields.forEach(subfield => {
          var _a, _b;
          acc.push({
            name: subfield.name,
            value: ((_a = subfield.inputType) === null || _a === void 0 ? void 0 : _a.toLowerCase()) == 'checkbox' ? 'false' : null,
            isDuplicate: subfield.isDuplicateInput || false,
            type: ((_b = field.inputType) === null || _b === void 0 ? void 0 : _b.toLowerCase()) == 'togglecheckbox'
              ? 'togglecheckbox'
              : null
          });
        });
      }
      else {
        acc.push({
          name: field.name,
          value: ((_b = field.inputType) === null || _b === void 0 ? void 0 : _b.toLowerCase()) == 'checkbox' ? 'false' : null,
          isDuplicate: field.isDuplicateInput || false,
          type: ((_c = field.inputType) === null || _c === void 0 ? void 0 : _c.toLowerCase()) == 'checkboxgroup' ? 'checkboxgroup' : null
        });
      }
      return acc;
    }, []);
    if (this.btag)
      this.addBtagValue();
    // Set the list of actions
    this.listOfActions = config.content.actions.map(action => action);
    this.registrationID = config.content.registrationID;
    this.registrationStep = config.content.step;
    if (this.listOfActions.some(action => action == '/register')) {
      this.lastStep = this.registrationStep;
    }
    ;
    // The translations for fields happens here. 
    if (this.translationUrl) {
      getTranslations(this.translationUrl).then(() => {
        this.listOfInputs.forEach(field => {
          var _a, _b;
          this.addTranslation(field);
          // Logic for field types that have subfields
          if (((_a = field.inputType) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === 'togglecheckbox') {
            field.data.subFields.forEach(subField => this.addTranslation(subField));
          }
          if (((_b = field.inputType) === null || _b === void 0 ? void 0 : _b.toLowerCase()) === 'checkboxgroup') {
            this.addTranslation(field);
            field.data.subFields.forEach(subField => this.addTranslation(subField));
          }
          return field;
        });
      })
        .catch((error) => {
        console.error('Failed to fetch translations:', error);
      }).finally(() => {
        this.forms = [...this.forms, { [this.registrationStep]: this.listOfInputs }];
      });
    }
    else {
      this.forms = [...this.forms, { [this.registrationStep]: this.listOfInputs }];
    }
    // Add the step to the registrationStepsData
    this.registrationStepsState.regId = this.registrationID;
    if (!this.registrationStepsState[this.registrationStep]) {
      this.registrationStepsState[this.registrationStep] = {
        fields: [],
        fieldsValidity: [],
        registerUserData: {},
        actions: []
      };
    }
  }
  addBtagValue() {
    const btagField = this.listOfInputs.find(input => input.name.toLowerCase() === 'btag');
    if (btagField) {
      btagField.defaultValue = this.btag;
    }
    const btagValue = this.listOfInputValues.find(input => input.name.toLowerCase() === 'btag');
    if (btagValue) {
      btagValue.value = this.btag;
    }
  }
  addTranslation(field) {
    if (TRANSLATIONS[this.language][field.name]) {
      Object.keys(TRANSLATIONS[this.language][field.name]).forEach((key) => {
        field[key] = TRANSLATIONS[this.language][field.name][key];
      });
    }
  }
  setInitialValidStatus(field) {
    var _a, _b;
    // Input type checkbox, with no validation are valid
    if (((_a = field.inputType) === null || _a === void 0 ? void 0 : _a.toLowerCase()) == 'checkbox' && ((_b = field.validate) === null || _b === void 0 ? void 0 : _b.mandatory) == false) {
      return true;
    }
    //Inputs that have default value are valid.
    if (field.defaultValue !== null) {
      return true;
    }
    return false;
  }
  stepChange(action) {
    const stepNum = parseInt(this.registrationStep.replace('Step', ''));
    if (action === 'increment') {
      return 'Step' + (stepNum + 1);
    }
    if (action === 'decrement') {
      return 'Step' + (stepNum - 1);
    }
  }
  getInvalidStatus(listOfInputs) {
    return listOfInputs.filter(input => input.isValid == false).length > 0;
  }
  renderForm() {
    return this.forms.map((form, index) => {
      return h("form", { action: '.', id: `RegistrationForm${this.registrationStep}`, class: `registration__form ${this.registrationStep !== `Step${index + 1}` ? 'hidden' : ''}`, ref: el => this.form = el },
        form[this.registrationStep] && form[this.registrationStep].map(input => h("general-input", { type: input.inputType, name: input.name, displayName: input.displayName, validation: input.validate, action: input.action || null, options: input.data
            ? (input.inputType.toLowerCase() == 'checkboxgroup' || input.inputType.toLowerCase() == 'togglecheckbox')
              ? input.data.subFields
              : input.data.values
            : [], defaultValue: input.defaultValue, autofilled: input.autofill, emitValue: this.emitValue, language: this.language, isDuplicateInput: input.isDuplicateInput, "client-styling": this.clientStyling, tooltip: input.tooltip, placeholder: input.placeholder == null ? '' : input.placeholder, dateFormat: this.dateFormat, "translation-url": this.translationUrl })),
        this.buttonInsideForm && this.renderButtons(),
        h("div", { class: 'registration__wrapper--flex' },
          h("p", { class: 'registration__error-message', innerHTML: this.errorMessage })));
    });
  }
  ;
  renderButtons() {
    return (h("div", { class: `registration__buttons-wrapper ${this.autofilled ? 'registration__buttons-wrapper--autofilled' : ''}` },
      this.isLoadingPOST
        && h("slot", { name: 'spinner' })
        && h("svg", { class: "spinner", viewBox: "0 0 50 50" },
          h("circle", { class: "path", cx: "25", cy: "25", r: "20", fill: "none", "stroke-width": "5" })),
      !this.isLoadingPOST && h("button", { class: `registration__button registration__button--next ${this.isFormValid ? '' : 'registration__button--disabled'}`, type: 'submit', form: `RegistrationForm${this.registrationStep}`, onClick: (e) => this.nextHandler(e), disabled: !this.isFormValid }, this.lastStep === this.registrationStep ? translate('doneButton', this.language) : translate('nextButton', this.language)),
      h("button", { class: `registration__button registration__button--back ${this.registrationStep == 'Step1' ? 'registration__button--first-step' : ''}`, onClick: (e) => this.backHandler(e) }, translate('backButton', this.language))));
  }
  render() {
    if (this.isLoading) {
      return h("p", null, "Please wait, loading ...");
    }
    return (h("div", { class: `registration  registration__${this.registrationStep}` },
      this.renderForm(),
      !this.buttonInsideForm && this.renderButtons()));
  }
  static get is() { return "general-registration"; }
  static get encapsulation() { return "shadow"; }
  static get originalStyleUrls() { return {
    "$": ["general-registration.scss"]
  }; }
  static get styleUrls() { return {
    "$": ["general-registration.css"]
  }; }
  static get properties() { return {
    "endpoint": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": true,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "NorWAy Endpoint for all the calls."
      },
      "attribute": "endpoint",
      "reflect": true
    },
    "language": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Currently selected language"
      },
      "attribute": "language",
      "reflect": true,
      "defaultValue": "'en'"
    },
    "clientStyling": {
      "type": "string",
      "mutable": true,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Client custom styling via inline styles"
      },
      "attribute": "client-styling",
      "reflect": true,
      "defaultValue": "''"
    },
    "clientStylingUrl": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Client custom styling via url"
      },
      "attribute": "client-styling-url",
      "reflect": true,
      "defaultValue": "''"
    },
    "translationUrl": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Translations via URL"
      },
      "attribute": "translation-url",
      "reflect": true,
      "defaultValue": "''"
    },
    "dateFormat": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Date format for date picker"
      },
      "attribute": "date-format",
      "reflect": true
    },
    "buttonInsideForm": {
      "type": "boolean",
      "mutable": false,
      "complexType": {
        "original": "boolean",
        "resolved": "boolean",
        "references": {}
      },
      "required": true,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Boolean that decides the position of the button. e.g. button inside -- true / outside -- false the form."
      },
      "attribute": "button-inside-form",
      "reflect": true
    },
    "btag": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Affiliate code to be passed in and sent in the registration."
      },
      "attribute": "btag",
      "reflect": true,
      "defaultValue": "null"
    }
  }; }
  static get states() { return {
    "errorMessage": {},
    "isFormValid": {},
    "isLoading": {},
    "isLoadingPOST": {},
    "registrationStep": {},
    "forms": {},
    "limitStylingAppends": {},
    "autofilled": {}
  }; }
  static get events() { return [{
      "method": "registrationWidgetLoaded",
      "name": "registrationWidgetLoaded",
      "bubbles": true,
      "cancelable": true,
      "composed": true,
      "docs": {
        "tags": [],
        "text": ""
      },
      "complexType": {
        "original": "any",
        "resolved": "any",
        "references": {}
      }
    }, {
      "method": "registrationStepUpdated",
      "name": "registrationStepUpdated",
      "bubbles": true,
      "cancelable": true,
      "composed": true,
      "docs": {
        "tags": [],
        "text": ""
      },
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      }
    }]; }
  static get elementRef() { return "host"; }
  static get watchers() { return [{
      "propName": "registrationStep",
      "methodName": "sendStep"
    }, {
      "propName": "forms",
      "methodName": "setFormValidity"
    }, {
      "propName": "btag",
      "methodName": "addBtag"
    }]; }
  static get listeners() { return [{
      "name": "sendValidityState",
      "method": "checkInputsValidityHandler",
      "target": undefined,
      "capture": false,
      "passive": false
    }, {
      "name": "sendInputValue",
      "method": "getInputsValueHandler",
      "target": undefined,
      "capture": false,
      "passive": false
    }]; }
}
