import { DeesElement, html, property, customElement, css, type TemplateResult } from '@design.estate/dees-element';
import { idpElementStyles } from './tokens.js';
import './idp-input.js';
import './idp-checkbox.js';

export type TIdpFormStatus = 'idle' | 'pending' | 'success' | 'error';
export type TIdpFormData = Record<string, string | boolean>;

export interface IIdpFormSubmitEventDetail {
  data: TIdpFormData;
  form: IdpForm;
}

type TFormControl = HTMLElement & {
  name?: string;
  key?: string;
  value?: string;
  checked?: boolean;
  validate?: () => boolean;
};

declare global {
  interface HTMLElementTagNameMap {
    'idp-form': IdpForm;
  }
}

@customElement('idp-form')
export class IdpForm extends DeesElement {
  public static demo = () => html`
    <idp-form>
      <idp-input name="email" label="Email" type="email" required></idp-input>
      <idp-form-submit>Continue</idp-form-submit>
    </idp-form>
  `;
  public static demoGroups = ['idp.global v3 primitives'];

  @property({ type: String, reflect: true })
  public accessor status: TIdpFormStatus = 'idle';

  @property({ type: String })
  public accessor statusMessage = '';

  @property({ type: Boolean, reflect: true })
  public accessor disabled = false;

  public static styles = [
    ...idpElementStyles,
    css`
      :host {
        display: block;
      }
      form {
        display: flex;
        flex-direction: column;
        gap: 16px;
      }
      ::slotted(idp-form-submit) {
        margin-top: 2px;
      }
      .status {
        padding: 11px 13px;
        border-radius: 10px;
        border: 1px solid var(--idp-border);
        background: var(--idp-muted);
        color: var(--idp-muted-fg);
        font-size: 13px;
        line-height: 1.45;
      }
      .status.pending {
        border-color: color-mix(in srgb, var(--idp-accent), transparent 60%);
        color: var(--idp-accent);
      }
      .status.success {
        border-color: color-mix(in srgb, var(--idp-ok), transparent 60%);
        color: var(--idp-ok);
      }
      .status.error {
        border-color: color-mix(in srgb, var(--idp-destructive), transparent 60%);
        color: var(--idp-destructive);
      }
    `,
  ];

  public setStatus(statusArg: TIdpFormStatus, messageArg = '') {
    this.status = statusArg;
    this.statusMessage = messageArg;
  }

  public resetStatus() {
    this.setStatus('idle', '');
  }

  public submit() {
    this.handleSubmit();
  }

  private getControls() {
    return Array.from(this.querySelectorAll('idp-input, idp-checkbox')) as TFormControl[];
  }

  private validateControls() {
    return this.getControls().every((controlArg) => controlArg.validate ? controlArg.validate() : true);
  }

  private getFormData(): TIdpFormData {
    const data: TIdpFormData = {};
    for (const control of this.getControls()) {
      const name = control.name || control.key;
      if (!name) {
        continue;
      }

      if (typeof control.checked === 'boolean') {
        data[name] = control.checked;
      } else {
        data[name] = control.value || '';
      }
    }
    return data;
  }

  private handleSubmitRequest(eventArg: Event) {
    eventArg.preventDefault();
    eventArg.stopPropagation();
    this.handleSubmit();
  }

  private handleSubmit(eventArg?: Event) {
    eventArg?.preventDefault();
    if (this.disabled || this.status === 'pending') {
      return;
    }
    if (!this.validateControls()) {
      this.setStatus('error', 'Please check the highlighted fields.');
      return;
    }

    this.dispatchEvent(new CustomEvent<IIdpFormSubmitEventDetail>('idp-submit', {
      detail: {
        data: this.getFormData(),
        form: this,
      },
      bubbles: true,
      composed: true,
    }));
  }

  public render(): TemplateResult {
    return html`
      <form novalidate @submit=${this.handleSubmit} @idp-form-submit-request=${this.handleSubmitRequest}>
        <slot></slot>
        ${this.statusMessage
          ? html`<div class="status ${this.status}" role="status">${this.statusMessage}</div>`
          : html``}
      </form>
    `;
  }
}
