import '@operato/i18n/ox-i18n.js'

import { html, nothing } from 'lit'
import { startAuthentication } from '@simplewebauthn/browser'

import { i18next } from '@operato/i18n'
import { notify } from '@operato/layout'

import { AbstractAuthPage } from './abstract-auth-page.js'

const isAvailableWebauthn = 'PublicKeyCredential' in window

interface AssertionResponse {
  id: string
  rawId?: number[]
  response: {
    authenticatorData: string
    clientDataJSON: string
    signature: string
    userHandle: string | null
  }
  type: PublicKeyCredentialType
  authenticatorAttachment?: AuthenticatorAttachment
}

export abstract class AbstractSign extends AbstractAuthPage {
  async submit() {
    this.formEl.submit()
  }

  updated(changed) {
    super.updated(changed)

    if (changed.has('message')) {
      if (!this.message) {
        this.hideSnackbar()
      } else {
        this.showSnackbar({
          level: 'error',
          timer: -1
        })
      }
    }
  }

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

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

      <div class="field">
        <md-filled-text-field
          name="username"
          type="text"
          label=${String(i18next.t('field.user-id or email'))}
          required
          .value=${username}
          autocomplete=${autocompletable ? 'username' : 'off'}
          autocapitalize="off"
          pattern="^(?:[A-Za-z0-9]*|[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+.[A-Za-z]{2,})$"
          @input=${(e: Event) => {
            const target = e.target as HTMLInputElement
            if (target.validity.typeMismatch) {
              target.setCustomValidity(i18next.t('text.invalid-username'))
            } else {
              target.setCustomValidity('')
            }
          }}
          ><md-icon slot="leading-icon">id_card</md-icon></md-filled-text-field
        >
      </div>
      <div class="field">
        <md-filled-text-field
          name="password"
          type="password"
          label=${String(i18next.t('field.password'))}
          autocomplete=${autocompletable ? 'current-password' : 'off'}
          required
          ><md-icon slot="leading-icon">password</md-icon></md-filled-text-field
        >
      </div>

      <div class="submit-buttons-container">
        <md-elevated-button class="submit-button" type="button" raised @click=${e => this._onSubmit(e)}>
          <ox-i18n msgid="field.${this.pageName}"> </ox-i18n>
        </md-elevated-button>
        ${isAvailableWebauthn
          ? html` <md-icon class="fingerprint" raised @click=${e => this.authenticateUser()}> fingerprint </md-icon>`
          : nothing}
      </div>
    `
  }

  async authenticateUser() {
    try {
      const options = await fetch('/auth/signin-webauthn/challenge').then(res => res.json())
      const assertionResp = await startAuthentication(options)
      const verification = await fetch('/auth/signin-webauthn', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify(assertionResp)
      }).then(res => res.json())

      if (verification.verified) {
        const { redirectURL } = verification

        if (redirectURL) {
          window.location.href = redirectURL
        }
      } else {
        notify({
          level: 'error',
          message: verification.message
        })
      }
    } catch (error) {
      notify({
        level: 'error',
        message: i18next.t('error.authn verification failed')
      })
    }
  }
}
