import '@material/mwc-button'
import '@material/mwc-icon'
import '@material/mwc-icon-button'
import '@material/mwc-textfield'
import '@operato/lottie-player'
import '@operato/i18n/ox-i18n.js'
import '@operato/i18n/ox-i18n-selector.js'
import '@operato/layout/ox-snack-bar.js'

import { css, html, LitElement, nothing } from 'lit'
import { property, query, state } from 'lit/decorators.js'

import { i18next, localize } from '@operato/i18n'
import { ScrollbarStyles } from '@operato/styles'
import { isSafari } from '@operato/utils'

import { AUTH_STYLE_SIGN } from '../auth-style-sign.js'

export abstract class AbstractAuthPage extends localize(i18next)(LitElement) {
  static styles = [
    ScrollbarStyles,
    css`
      :host {
        position: relative;
        overflow: hidden;

        display: flex;
        flex-direction: row;

        width: 100vw;
        height: 100vh;
        height: 100dvh;
      }
      .content {
        flex: 1;
        overflow: auto;
      }

      [home] {
        position: absolute;
        top: 10px;
        left: 10px;
        font-size: 2em;
        color: white;
      }

      [hidden] {
        display: none;
      }

      #snackbar {
        width: 100%;
        z-index: 10;
      }

      @media print {
        :host {
          width: 100%;
          height: 100%;
          min-height: 100vh;
          min-height: 100dvh;
        }
      }
    `,
    AUTH_STYLE_SIGN
  ]

  @property({ type: Object }) data: any
  @property({ type: String }) message?: string
  @property({ type: Object }) detail: any
  @property({ type: String }) redirectTo?: string

  @query('#form') formEl!: HTMLFormElement

  private _applicationMeta?: {
    icon: string
    title: string
    description: string
  }

  render() {
    const { disableUserFavoredLanguage, languages } = this.data || {}
    var { icon, title, description } = this.applicationMeta

    return html`
      <div class="content">
        <div class="wrap">
          <div class="auth-brand">
            <img src=${icon} />
            <strong class="name">${title}</strong>
            <span class="welcome-msg">${description}</span>
          </div>

          <div class="auth-form">
            <h3><ox-i18n msgid="title.${this.pageName}"></ox-i18n></h3>

            <form
              id="form"
              action="${this.actionUrl}"
              method="post"
              @keypress=${e => {
                if (e.key == 'Enter') this._onSubmit(e)
              }}
            >
              ${this.formfields}
            </form>
            ${this.links}
            ${!disableUserFavoredLanguage
              ? html` <div id="locale-area">
                  <label for="locale-selector"><mwc-icon>language</mwc-icon></label>
                  <ox-i18n-selector
                    id="locale-selector"
                    value=${i18next.language || 'en-US'}
                    .languages=${languages}
                    @change=${e => {
                      var locale = e.detail
                      if (!locale) return

                      i18next.changeLanguage(locale)
                    }}
                  ></ox-i18n-selector>
                </div>`
              : nothing}
          </div>
        </div>

        <mwc-icon-button home icon="home" @click=${e => (window.location.href = '/')}></mwc-icon-button>
        <ox-snack-bar id="snackbar" level="error" .message=${this.message}></ox-snack-bar>

        ${isSafari()
          ? html``
          : html`
              <div class="lottie-container">
                <lottie-player autoplay loop src="../../assets/images/background-animation.json"></lottie-player>
              </div>
            `}
      </div>
    `
  }

  firstUpdated() {
    setTimeout(() => {
      ;(this.renderRoot.querySelector('mwc-textfield') as any).focus()
    }, 100)

    this.formEl.reset = () => {
      this.formElements.filter(el => !(el.hidden || el.type == 'hidden')).forEach(el => (el.value = ''))
    }
  }

  updated(changed) {
    if (changed.has('data') && this.data) {
      this.message = this.data.message
      this.redirectTo = this.data.redirectTo
    }
  }

  abstract get pageName(): string
  abstract get actionUrl(): string

  get formElements(): HTMLInputElement[] {
    return Array.from(this.formEl.querySelectorAll('[name]'))
  }

  get formfields() {
    const email = this.data?.email || ''

    return html`
      <input id="redirectTo" type="hidden" name="redirectTo" .value=${this.redirectTo || '/'} />

      <div class="field">
        <mwc-textfield
          name="email"
          type="email"
          label=${String(i18next.t('field.email'))}
          required
          .value=${email}
          .validationMessage=${String(i18next.t('text.invalid-email'))}
          autocomplete="username"
          autocapitalize="off"
        ></mwc-textfield>
      </div>
      <div class="field">
        <mwc-textfield
          name="password"
          type="password"
          label=${String(i18next.t('field.password'))}
          autocomplete="current-password"
          required
        ></mwc-textfield>
      </div>

      <mwc-button class="ui" type="submit" raised @click=${e => this._onSubmit(e)}>
        <ox-i18n msgid="field.${this.pageName}"> </ox-i18n>
      </mwc-button>
    `
  }

  get links() {
    const { disableUserSignupProcess, ssoLinks = [] } = this.data || {}

    return html`
      ${!disableUserSignupProcess
        ? html`
            <a class="link" href="/auth/signup">
              <mwc-button icon="add_task"><ox-i18n msgid="field.sign up"></ox-i18n></mwc-button>
            </a>
            <a class="link" href="/auth/forgot-password">
              <mwc-button icon="lock_open"><ox-i18n msgid="field.forgot-password"></ox-i18n></mwc-button>
            </a>
          `
        : nothing}
      ${ssoLinks.map(
        sso => html`
          <a class="link" href=${sso.link}>
            <mwc-button icon="badge">${i18next.t('label.signin with', { title: sso.title })}</mwc-button>
          </a>
        `
      )}
    `
  }

  async _onSubmit(e) {
    if (this.checkValidity()) {
      this.submit()
    }
  }

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

  abstract submit()

  showSnackbar({ level, message, timer = 3000 }: { level?: string; message?: string; timer?: number } = {}) {
    const snackbar = this.renderRoot.querySelector('#snackbar') as HTMLElement & {
      level: string
      message: string
      active: boolean
    }

    if (level) snackbar.level = level
    if (message) snackbar.message = message
    snackbar.active = true

    if (timer > -1)
      setTimeout(() => {
        this.hideSnackbar()
      }, timer)
  }

  hideSnackbar() {
    const snackbar = this.renderRoot.querySelector('#snackbar') as HTMLElement & {
      level: string
      message: string
      active: boolean
    }

    snackbar.active = false
  }

  get applicationMeta() {
    if (!this._applicationMeta) {
      var iconLink: HTMLLinkElement | null = document.querySelector('link[rel="application-icon"]')
      var titleMeta: HTMLMetaElement | null = document.querySelector('meta[name="application-name"]')
      var descriptionMeta: HTMLMetaElement | null = document.querySelector('meta[name="application-description"]')

      this._applicationMeta = {
        icon: iconLink?.href || '',
        title: titleMeta?.content || 'Things Factory',
        description: descriptionMeta?.content || 'Reimagining Software'
      }
    }

    return this._applicationMeta
  }
}
