<script setup lang="ts">
import { useMutation } from '@vue/apollo-composable';
import {
  ConsumeLoginTokenDocument,
  RequestLoginCodeDocument,
  VerifyLoginCodeDocument,
} from '~/composables/graphql/generated';

const config = useRuntimeConfig();
const route = useRoute();
const authCookieName = config.public.authCookieName || 'fregat_auth_token';
const authCookie = useCookie<string | null>(authCookieName, {
  sameSite: 'lax',
  maxAge: 60 * 60 * 24 * 30,
});

const step = ref<'request' | 'verify'>('request');
const email = ref('');
const challengeToken = ref('');
const maskedEmail = ref('');
const expiresAt = ref('');
const code = ref('');
const feedback = ref('');
const feedbackTone = ref<'success' | 'error'>('success');
const autoRequestTimer = ref<ReturnType<typeof setTimeout> | null>(null);
const lastRequestedEmail = ref('');

const requestCodeMutation = useMutation(RequestLoginCodeDocument, { throws: 'never' });
const verifyCodeMutation = useMutation(VerifyLoginCodeDocument, { throws: 'never' });
const consumeLoginTokenMutation = useMutation(ConsumeLoginTokenDocument, { throws: 'never' });

const telegramBotUrl = computed(() => config.public.telegramBotUrl || '');
const maxBotUrl = computed(() => config.public.maxBotUrl || '');

const normalizedEmail = computed(() => email.value.trim().toLowerCase());
const isEmailReady = computed(() => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(normalizedEmail.value));

function buildBotLoginUrl(baseUrl: string) {
  if (!isEmailReady.value || !baseUrl) {
    return '';
  }

  const payload = encodeURIComponent(`login:${normalizedEmail.value}`);
  const separator = baseUrl.includes('?') ? '&' : '?';
  return `${baseUrl}${separator}start=${payload}`;
}

const telegramLoginUrl = computed(() => buildBotLoginUrl(telegramBotUrl.value));
const maxLoginUrl = computed(() => buildBotLoginUrl(maxBotUrl.value));

async function finalizeSession(accessToken: string) {
  authCookie.value = accessToken;
}

async function navigateAfterLogin(user: { company?: { id: string } | null }) {
  if (!user.company?.id) {
    await navigateTo('/profile');
    return;
  }

  await navigateTo('/products');
}

function clearAutoRequestTimer() {
  if (!autoRequestTimer.value) {
    return;
  }

  clearTimeout(autoRequestTimer.value);
  autoRequestTimer.value = null;
}

function normalizeApolloErrorMessage(message: string) {
  if (message.includes('User for this destination was not found.')) {
    return 'Пользователь с таким e-mail не найден. Вход доступен только для созданных аккаунтов.';
  }
  return message;
}

function requestCodeFailedMessage() {
  const mutationError = requestCodeMutation.error.value;
  if (!mutationError) {
    return 'Не получилось отправить код.';
  }

  const firstGraphqlError = mutationError.graphQLErrors[0]?.message;
  if (firstGraphqlError) {
    return normalizeApolloErrorMessage(firstGraphqlError);
  }

  if (mutationError.message) {
    return normalizeApolloErrorMessage(mutationError.message);
  }

  return 'Не получилось отправить код.';
}

async function requestCode() {
  if (!isEmailReady.value) {
    feedback.value = 'Введите корректный email.';
    feedbackTone.value = 'error';
    return;
  }
  if (requestCodeMutation.loading.value) {
    return;
  }
  clearAutoRequestTimer();

  feedback.value = '';
  const result = await requestCodeMutation.mutate({
    input: {
      channel: 'EMAIL',
      destination: normalizedEmail.value,
    },
  });

  const payload = result?.data?.requestLoginCode;
  if (!payload) {
    feedback.value = requestCodeFailedMessage();
    feedbackTone.value = 'error';
    return;
  }

  lastRequestedEmail.value = normalizedEmail.value;
  challengeToken.value = payload.challengeToken;
  maskedEmail.value = payload.destination;
  expiresAt.value = new Date(payload.expiresAt).toLocaleString();
  code.value = '';
  feedback.value = `Код отправлен на ${payload.destination}.`;
  feedbackTone.value = 'success';
  step.value = 'verify';
}

async function verifyCode() {
  if (!challengeToken.value || !code.value.trim()) {
    feedback.value = 'Введите код из письма.';
    feedbackTone.value = 'error';
    return;
  }

  feedback.value = '';
  const result = await verifyCodeMutation.mutate({
    input: {
      challengeToken: challengeToken.value,
      code: code.value.trim(),
    },
  });

  const payload = result?.data?.verifyLoginCode;
  if (!payload) {
    feedback.value = 'Не получилось выполнить вход.';
    feedbackTone.value = 'error';
    return;
  }

  await finalizeSession(payload.accessToken);
  await navigateAfterLogin(payload.user);
}

async function consumeLoginToken(loginToken: string) {
  feedback.value = '';
  const result = await consumeLoginTokenMutation.mutate({
    token: loginToken,
  });
  const payload = result?.data?.consumeLoginToken;
  if (!payload) {
    feedback.value = 'Временный токен входа недействителен.';
    feedbackTone.value = 'error';
    return;
  }
  await finalizeSession(payload.accessToken);
  await navigateAfterLogin(payload.user);
}

function scheduleAutoRequest() {
  clearAutoRequestTimer();

  if (step.value !== 'request') {
    return;
  }
  if (!isEmailReady.value) {
    return;
  }
  if (normalizedEmail.value === lastRequestedEmail.value) {
    return;
  }

  autoRequestTimer.value = setTimeout(() => {
    void requestCode();
  }, 450);
}

function onEmailBlur() {
  if (step.value !== 'request') {
    return;
  }
  if (!isEmailReady.value) {
    return;
  }
  if (normalizedEmail.value === lastRequestedEmail.value) {
    return;
  }

  void requestCode();
}

watch([normalizedEmail, step], () => {
  if (step.value !== 'request') {
    clearAutoRequestTimer();
    return;
  }

  scheduleAutoRequest();
});

onMounted(async () => {
  const loginToken = typeof route.query.login_token === 'string' ? route.query.login_token : '';
  if (loginToken) {
    await consumeLoginToken(loginToken);
  }
});

onBeforeUnmount(() => {
  clearAutoRequestTimer();
});
</script>

<template>
  <section class="mx-auto flex min-h-[calc(100vh-4rem)] w-full max-w-3xl items-center py-8">
    <div class="card w-full border border-base-300/60 bg-base-100 shadow-xl">
      <div class="card-body p-5 md:p-8">
        <div class="mb-4 text-center">
          <h1 class="text-3xl font-extrabold">Вход в личный кабинет</h1>
        </div>

        <div v-if="step === 'request'" class="space-y-4">
          <fieldset class="fieldset">
            <legend class="fieldset-legend text-base font-semibold">E-mail</legend>
            <input
              v-model="email"
              type="email"
              class="input input-bordered w-full"
              placeholder="name@company.com"
              @keydown.enter.prevent="requestCode"
              @blur="onEmailBlur"
            >
          </fieldset>

          <div class="grid gap-2 sm:grid-cols-2">
            <a
              :href="telegramLoginUrl || undefined"
              target="_blank"
              rel="noopener noreferrer"
              class="btn btn-secondary"
              :class="{ 'btn-disabled pointer-events-none': !telegramLoginUrl }"
            >
              Войти через Telegram
            </a>
            <a
              :href="maxLoginUrl || undefined"
              target="_blank"
              rel="noopener noreferrer"
              class="btn btn-accent"
              :class="{ 'btn-disabled pointer-events-none': !maxLoginUrl }"
            >
              Войти через Max
            </a>
          </div>

          <p v-if="requestCodeMutation.loading.value" class="text-sm text-base-content/70">
            Проверяем e-mail и отправляем код...
          </p>
        </div>

        <div v-else class="space-y-4">
          <p class="text-sm text-base-content/70">E-mail: {{ maskedEmail }}</p>

          <fieldset class="fieldset">
            <legend class="fieldset-legend text-base font-semibold">Код</legend>
            <input
              v-model="code"
              type="text"
              maxlength="6"
              class="input input-bordered w-full"
              placeholder="123456"
              @keydown.enter.prevent="verifyCode"
            >
          </fieldset>

          <button
            class="btn btn-primary w-full"
            :disabled="verifyCodeMutation.loading.value"
            @click="verifyCode"
          >
            {{ verifyCodeMutation.loading.value ? 'Проверяем…' : 'Войти' }}
          </button>

          <button
            class="btn btn-ghost w-full"
            @click="step = 'request'; code = ''; feedback = ''; challengeToken = ''; maskedEmail = ''"
          >
            Изменить e-mail
          </button>

          <p class="text-xs text-base-content/60">Код действует до {{ expiresAt }}</p>
        </div>

        <div
          v-if="feedback"
          class="alert mt-2"
          :class="feedbackTone === 'success' ? 'alert-success' : 'alert-error'"
        >
          {{ feedback }}
        </div>
      </div>
    </div>
  </section>
</template>
