<template>
  <q-page class="flex flex-center bg-grey-3">
    <q-card style="width: 300px">
      <!-- лого -->
      <div style="margin-top: -50px" class="text-center">
        <q-avatar class="shadow-2" size="100px">
          <img :src="props.logo" />
        </q-avatar>
      </div>

      <!-- вход по email -->
      <q-card-section>
        <q-input
          v-model="email"
          type="email"
          placeholder="E-mail"
          debounce="300"
          :rules="[checkEmail]"
          :error-message="t`Помилковий формат email`"
          :hint="t`на цю адресу буде надіслано код`"
          outlined
          autofocus>
          <template #prepend>
            <q-icon name="mail" />
          </template>
          <template v-if="email && checkEmail(email) && browserSupportsWebAuthn()" #append>
            <q-btn @click="biometry(email)" padding="none" flat icon="fingerprint" />
          </template>
        </q-input>

        <q-btn
          v-if="email && checkEmail(email)"
          @click="emailSubmit"
          :label="t`Отримати код`"
          :loading="emailLoading"
          class="full-width q-mt-md"
          padding="md"
          color="primary" />
      </q-card-section>

      <!-- или -->
      <q-card-section class="row items-center q-gutter-x-md">
        <q-separator class="col" />
        <div>{{ t`АБО` }}</div>
        <q-separator class="col" />
      </q-card-section>

      <!-- вход по логину/паролю -->
      <q-card-section>
        <q-form @submit="loginSubmit" class="full-width q-gutter-y-md" autocomplete="on">
          <div v-if="loginError" class="text-white text-red bg-red-1 q-pa-xs text-center">{{ loginError }}</div>

          <q-input id="login" v-model.trim="login" type="login" autocomplete="username" :label="t`Логін`" outlined>
            <template #prepend>
              <q-icon name="person" />
            </template>
            <template v-if="login && browserSupportsWebAuthn()" #append>
              <q-btn @click="biometry(login, 'login')" padding="none" flat icon="fingerprint" />
            </template>
          </q-input>
          <q-input
            id="password"
            v-model="password"
            :type="isPwd ? 'password' : 'text'"
            autocomplete="current-password"
            :label="t`Пароль`"
            outlined>
            <template #prepend>
              <q-icon name="vpn_key" />
            </template>
            <template #append>
              <q-icon @click="isPwd = !isPwd" :name="isPwd ? 'visibility_off' : 'visibility'" class="cursor-pointer" />
            </template>
          </q-input>

          <q-btn
            v-if="login && password && password.length > 4"
            :loading="loginLoading"
            type="submit"
            :label="t`Увійти`"
            class="full-width q-mt-md"
            padding="md"
            color="primary" />
        </q-form>

        <n-forgot-pass />
      </q-card-section>

      <!-- или -->
      <q-card-section v-if="telegram || apple || google" class="row items-center q-gutter-x-md">
        <q-separator class="col" />
        <div>{{ t`АБО` }}</div>
        <q-separator class="col" />
      </q-card-section>

      <q-card-section v-if="telegram || apple || google" class="q-gutter-y-md">
        <!-- телеграм логин -->
        <div v-if="google">
          <n-login-google :id="google" @authorized="authorized" />
        </div>

        <!-- телеграм логин -->
        <div v-if="telegram">
          <n-login-telegram :id="telegram" @authorized="authorized" />
        </div>

        <!-- apple логин -->
        <div v-if="apple">
          <n-login-apple :id="apple" @authorized="authorized" />
        </div>
      </q-card-section>

      <!-- Слот для содержимого -->
      <slot />
    </q-card>
  </q-page>
</template>

<script setup>
import tfm from '@nitra/tfm'
import { autoLogin, checkToken, defaultLogin } from '@nitra/vite-boot/token'
import { browserSupportsWebAuthn, startAuthentication } from '@simplewebauthn/browser'
import { date, Notify } from 'quasar'
import { computed, ref } from 'vue'
import { useRouter } from 'vue-router'
import NForgotPass from './NForgotPass.vue'
import NLoginApple from './NLoginApple.vue'
import NLoginGoogle from './NLoginGoogle.vue'
import NLoginTelegram from './NLoginTelegram.vue'

const router = useRouter()

const baseUrl = import.meta.env.BASE_URL

const props = defineProps({
  logo: {
    type: String,
    default: 'https://cdn.jsdelivr.net/npm/@nitra/auth-components@2/assets/logo.jpeg'
  },
  google: {
    type: String,
    default: null
  },
  telegram: {
    type: String,
    default: null
  },
  // apple signin options
  apple: {
    type: String,
    default: null
  }
})

// событие когда пользователь авторизован
const emit = defineEmits(['authorized'])

// Авто авторизація якщо у користувача є коректний токен
autoLogin()

const t = tfm.bind({ tr: getTr() })

// ВХОД ПО EMAIL
const email = ref(localStorage.getItem('email') || '')
const emailLowerCased = computed(() => email.value.toLowerCase())
const emailLoading = ref(false)

// валидный ли адрес
const checkEmail = email => {
  if (!email) {
    return true
  }

  if (email.length > 320) {
    return false
  }

  const regex =
    /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/

  return regex.test(String(email).toLowerCase().trim())
}

// получить код
const emailSubmit = async () => {
  try {
    emailLoading.value = true

    const response = await fetch(`${baseUrl}auth/otp-email`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        email: emailLowerCased.value,
        href: globalThis.location.origin + '/code'
      })
    })
    const res = await response.json()

    if (res.error) {
      loginError.value = JSON.stringify(res.error)
    } else {
      localStorage.setItem('email', emailLowerCased.value)
      localStorage.setItem('email-otp-date', date.addToDate(new Date(), { minutes: 30 }))
      await router.push('/code')
    }
  } catch (error) {
    loginError.value = error.message
  } finally {
    emailLoading.value = false
  }
}

// ВХОД ПО ЛОГИНУ/ПАРОЛЮ
const login = ref(null)
const password = ref(null)
const isPwd = ref(true)
const loginLoading = ref(false)
const loginError = ref('')

// отправить логин/пароль
const loginSubmit = async () => {
  try {
    loginLoading.value = true
    loginError.value = ''

    const data = { login: login.value, pass: password.value }

    const response = await fetch(`${baseUrl}auth/send-login-pass`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(data)
    })

    const res = await response.json()

    if (res.token) {
      const check = checkToken(res.token)
      if (check.result === 'ok') {
        await defaultLogin(check.decoded, res.token)
      } else {
        loginError.value = t`Користувачу ${localStorage.getItem(
          'email'
        )} не дозволено входити в дане програмне забезпечення`
      }
    } else {
      if (JSON.stringify(res.error).includes('Incorrect auth')) {
        loginError.value = t`Помилковий логін або пароль`
      } else {
        loginError.value = t`Помилка: ${JSON.stringify(res.error)}`
      }
    }
  } catch (error) {
    loginError.value = error.message
  } finally {
    loginLoading.value = false
  }
}

/**
 *
 * @param {string} jwt - jwt token
 */
function authorized(jwt) {
  emit('authorized', jwt)
}

const biometry = async (user, type = 'email') => {
  try {
    // Отримуємо параметри реєстрації (зберігається challenge на сервері)
    const resp = await fetch(`${baseUrl}auth/generate-authentication-options`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        user,
        type
      })
    })
    const authOptions = await resp.json()
    if (!authOptions.challenge) {
      Notify.create({ type: 'warning', message: t`У користувача "${user}" немає зареєстрованих біометричних даних` })
      return
    }

    // Pass the options to the authenticator and wait for a response
    const authResp = await startAuthentication(authOptions)

    // POST the response to the endpoint that calls
    const verificationResp = await fetch(`${baseUrl}auth/verify-authentication`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(authResp)
    })

    // Wait for the results of verification
    const res = await verificationResp.json()

    if (res.verified && res.token) {
      const check = checkToken(res.token)
      if (check.result === 'ok') {
        await defaultLogin(check.decoded, res.token)
      } else {
        loginError.value = t`Користувачу ${user} не дозволено входити в дане програмне забезпечення`
      }
    } else {
      loginError.value = t`Користувачу ${user} не дозволено входити в дане програмне забезпечення`
    }
  } catch (error) {
    Notify.create({ type: 'negative', message: `${error}` })
  }
}

/**
 * LOCALIZATION
 * @returns {object} translations
 */
function getTr() {
  return {
    'на цю адресу буде надіслано код': { ru: 'на этот адрес будет отправлен код' },
    'Помилковий формат email': { ru: 'Некорректный формат email' },
    'Помилковий логін або пароль': { ru: 'Неверный логин или пароль' },
    'Отримати код': { ru: 'Получить код' },
    'Помилка: ': { ru: 'Ошибка: ' },
    АБО: { ru: 'ИЛИ' },
    Увійти: { ru: 'Войти' },
    Логін: { ru: 'Логин' },
    Пароль: { ru: 'Пароль' },
    'У користувача "': { ru: 'У пользователя "' },
    '" немає зареєстрованих біометричних даних': { ru: '" нет зарегистрированных биометрических данных' },
    'Користувачу ': { ru: 'Пользователю ' },
    ' не дозволено входити в дане програмне забезпечення': { ru: ' не разрешено входить в данное приложение' }
  }
}
</script>
