import { customElement, html, TemplateResult, DeesElement } from '@designestate/dees-element';
import * as domtools from '@designestate/dees-domtools';

import { DeesInputCheckbox } from './dees-input-checkbox.js';
import { DeesInputText } from './dees-input-text.js';
import { DeesInputQuantitySelector } from './dees-input-quantityselector.js';
import { DeesInputRadio } from './dees-input-radio.js';
import { DeesFormSubmit } from './dees-form-submit.js';

export type TFormElement = Array<
  DeesInputCheckbox | DeesInputText | DeesInputQuantitySelector | DeesInputRadio
>;

declare global {
  interface HTMLElementTagNameMap {
    'dees-form': DeesForm;
  }
}

@customElement('dees-form')
export class DeesForm extends DeesElement {
  public static demo = () => html`
    <dees-form
      style="display: block; margin:auto; max-width: 500px; padding: 20px"
      @formData=${async (eventArg) => {
        const form: DeesForm = eventArg.currentTarget;
        form.setStatus('pending', 'authenticating...');
        await domtools.plugins.smartdelay.delayFor(1000);
        form.setStatus('success', 'authenticated!');
      }}
    >
      <dees-input-text .required="${true}" key="hello1" label="a text"></dees-input-text>
      <dees-input-text .required="${true}" key="hello2" label="also a text"></dees-input-text>
      <dees-input-checkbox
        .required="${true}"
        key="hello3"
        label="another text"
      ></dees-input-checkbox>
      <dees-form-submit>Submit</dees-form-submit>
    </dees-form>
  `;

  public name: string = 'myform';
  public changeSubject = new domtools.rxjs.Subject();

  public render(): TemplateResult {
    return html`
      <style>
        :host {
          display: contents;
        }
      </style>
      <slot></slot>
    `;
  }

  public firstUpdated() {
    const formChildren = this.getFormChildren();
    this.checkRequiredStatus();
    for (const child of formChildren) {
      child.changeSubject.subscribe(async (elementArg: TFormElement) => {
        const valueObject = await this.gatherData();
        this.changeSubject.next(valueObject);
        console.log(valueObject);
        this.checkRequiredStatus();
      });
    }
  }

  public getFormChildren() {
    const children: Array<DeesElement> = this.children as any;
    const formChildren: TFormElement = [];

    for (const child of children) {
      if (
        child instanceof DeesInputCheckbox ||
        child instanceof DeesInputText ||
        child instanceof DeesInputQuantitySelector
      ) {
        formChildren.push(child);
      }
    }
    return formChildren;
  }

  public getSubmitButton() {
    const children: Array<DeesElement> = this.children as any;
    let submitButton: DeesFormSubmit;
    for (const childArg of children) {
      if (childArg instanceof DeesFormSubmit) {
        submitButton = childArg;
      }
    }
    return submitButton;
  }

  public async checkRequiredStatus() {
    console.log('checking the required status.');

    let requiredOK = true;
    for (const childArg of this.getFormChildren()) {
      if (childArg.required && !childArg.value) {
        requiredOK = false;
      }
    }
    if (this.getSubmitButton()) {
      this.getSubmitButton().disabled = !requiredOK;
    }
  }

  public async gatherData() {
    const children = this.getFormChildren();
    const valueObject: { [key: string]: string | number | boolean } = {};
    for (const child of children) {
      valueObject[child.key] = child.value;
    }
    return valueObject;
  }

  public async gatherAndDispatch() {
    const valueObject = await this.gatherData();
    const formDataEvent = new CustomEvent('formData', {
      detail: {
        data: valueObject,
      },
      bubbles: true,
    });
    this.dispatchEvent(formDataEvent);
    console.log('dispatched data:');
    console.log(valueObject);
  }

  public setStatus(
    visualStateArg: 'normal' | 'pending' | 'error' | 'success',
    textStateArg: string
  ) {
    const inputChildren = this.getFormChildren();
    const submitButton = this.getSubmitButton();

    switch (visualStateArg) {
      case 'normal':
        submitButton.disabled = false;
        submitButton.status = 'normal';
        for (const inputChild of inputChildren) {
          inputChild.disabled = false;
        }
        break;
      case 'pending':
        submitButton.disabled = true;
        submitButton.status = 'pending';
        for (const inputChild of inputChildren) {
          inputChild.disabled = true;
        }
        break;
      case 'success':
        submitButton.disabled = true;
        submitButton.status = 'success';
        for (const inputChild of inputChildren) {
          inputChild.disabled = true;
        }
        break;
      case 'error':
        submitButton.disabled = true;
        submitButton.status = 'error';
        for (const inputChild of inputChildren) {
          inputChild.disabled = true;
        }
        break;
    }

    submitButton.text = textStateArg;
  }
}