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

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 requestCodeMutation = useMutation(RequestLoginCodeDocument, { throws: 'never' });
const verifyCodeMutation = useMutation(VerifyLoginCodeDocument, { throws: 'never' });
const consumeLoginTokenMutation = useMutation(ConsumeLoginTokenDocument, { throws: 'never' });
const { openMessengerBot, pendingChannel } = useMessengerStart();
const {
  channel: messengerMiniAppChannel,
  channelLabel: messengerMiniAppChannelLabel,
  displayName: messengerMiniAppDisplayName,
  initData: messengerMiniAppInitData,
  isAvailable: isMessengerMiniApp,
} = useMessengerMiniApp();

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));
const canUseTelegramLogin = computed(() => messengerMiniAppChannel.value !== 'TELEGRAM' && Boolean(telegramBotUrl.value));
const canUseMaxLogin = computed(() => messengerMiniAppChannel.value !== 'MAX' && Boolean(maxBotUrl.value));
const hasMessengerButtons = computed(() => canUseTelegramLogin.value || canUseMaxLogin.value);
const nextPath = computed(() =>
  typeof route.query.next === 'string' && route.query.next.startsWith('/')
    ? route.query.next
    : '',
);
const telegramMiniAppMode = ref<'idle' | 'checking' | 'authenticated' | 'needs_email'>('idle');

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

async function navigateAfterLogin(user: { company?: { id: string } | null; companyId?: string | null }) {
  if (nextPath.value) {
    await navigateTo(nextPath.value);
    return;
  }

  if (!user.company?.id && !user.companyId) {
    await navigateTo('/profile');
    return;
  }

  await navigateTo('/');
}

function normalizeApolloErrorMessage(message: string) {
  if (message.includes('User for this destination was not found.')) {
    return 'Пользователь с таким e-mail не найден. Вход доступен только для созданных аккаунтов.';
  }
  if (message.includes('Telegram initData')) {
    return 'Не получилось проверить Telegram Mini App. Откройте кабинет из Telegram заново.';
  }
  if (message.includes('MAX initData')) {
    return 'Не получилось проверить MAX Mini App. Откройте кабинет из MAX заново.';
  }
  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;
  }

  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;
  }

  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 connectMessengerMiniApp();
  await navigateAfterLogin(payload.user);
}

function returnToRequestStep() {
  step.value = 'request';
  code.value = '';
  feedback.value = '';
  challengeToken.value = '';
  maskedEmail.value = '';
  expiresAt.value = '';
}

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);
  const nextPath = typeof route.query.next === 'string' ? route.query.next : '';
  if (nextPath.startsWith('/')) {
    await navigateTo(nextPath);
    return;
  }
  await navigateAfterLogin(payload.user);
}

function resolveMessengerMiniAppEndpoint(mode: 'session' | 'connect') {
  if (messengerMiniAppChannel.value === 'MAX') {
    return `/api/auth/max-mini-app/${mode}`;
  }

  return `/api/auth/telegram-mini-app/${mode}`;
}

function resolveMessengerMiniAppLabel() {
  return messengerMiniAppChannelLabel.value || 'Mini App';
}

async function connectMessengerMiniApp() {
  if (!isMessengerMiniApp.value || !messengerMiniAppInitData.value) {
    return;
  }
  if (telegramMiniAppMode.value === 'authenticated') {
    return;
  }

  try {
    await $fetch(resolveMessengerMiniAppEndpoint('connect'), {
      method: 'POST',
      body: {
        initData: messengerMiniAppInitData.value,
      },
    });
  } catch (error) {
    console.error('messenger mini app connect failed', error);
  }
}

async function tryMessengerMiniAppLogin() {
  if (!isMessengerMiniApp.value || !messengerMiniAppInitData.value) {
    return;
  }

  telegramMiniAppMode.value = 'checking';

  try {
    const payload = await $fetch<{
      ok: true;
      authenticated: boolean;
      accessToken?: string;
      user?: { company?: { id: string } | null; companyId?: string | null };
      telegramUser?: { displayName?: string };
      maxUser?: { displayName?: string };
    }>(resolveMessengerMiniAppEndpoint('session'), {
      method: 'POST',
      body: {
        initData: messengerMiniAppInitData.value,
      },
    });

    if (payload.authenticated && payload.accessToken && payload.user) {
      telegramMiniAppMode.value = 'authenticated';
      await finalizeSession(payload.accessToken);
      await navigateAfterLogin(payload.user);
      return;
    }

    telegramMiniAppMode.value = 'needs_email';
    const messengerUser = payload.maxUser ?? payload.telegramUser;
    feedback.value = messengerUser?.displayName
      ? `${messengerUser.displayName}, введите рабочий e-mail. После входа мы привяжем этот ${resolveMessengerMiniAppLabel()} к вашему кабинету.`
      : `Введите рабочий e-mail. После входа мы привяжем этот ${resolveMessengerMiniAppLabel()} к вашему кабинету.`;
    feedbackTone.value = 'success';
  } catch (error) {
    telegramMiniAppMode.value = 'idle';
    const message = typeof error === 'object' && error && 'data' in error && typeof error.data === 'object' && error.data && 'error' in error.data
      ? String(error.data.error || '')
      : error instanceof Error
        ? error.message
        : `Не получилось проверить ${resolveMessengerMiniAppLabel()}.`;
    feedback.value = normalizeApolloErrorMessage(message);
    feedbackTone.value = 'error';
  }
}

async function startMessengerLogin(channel: 'TELEGRAM' | 'MAX') {
  if (!isEmailReady.value) {
    feedback.value = 'Введите корректный email.';
    feedbackTone.value = 'error';
    return;
  }

  const baseUrl = channel === 'TELEGRAM' ? telegramBotUrl.value : maxBotUrl.value;
  if (!baseUrl) {
    feedback.value = 'Ссылка на бота пока не настроена.';
    feedbackTone.value = 'error';
    return;
  }

  feedback.value = '';
  await openMessengerBot({
    channel,
    baseUrl,
    email: normalizedEmail.value,
    redirectPath: `/profile/notifications/success?connected=${channel.toLowerCase()}`,
  });
}

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

  await tryMessengerMiniAppLogin();
});
</script>

<template>
  <section class="mx-auto flex w-full max-w-[540px] items-center justify-center py-6 md:py-10">
    <div class="surface-card w-full rounded-[32px] border border-white/70 px-6 py-6 shadow-[0_26px_70px_rgba(18,56,36,0.12)] md:px-8 md:py-8">
      <div class="space-y-6">
        <div class="space-y-3 text-center">
          <p class="text-[11px] font-bold uppercase tracking-[0.22em] text-[#6a8a76]">Фрегат</p>
          <div class="space-y-2">
            <h1 class="text-3xl font-black tracking-[-0.04em] text-[#123824] md:text-4xl">Вход</h1>
            <p class="text-sm leading-6 text-[#5c7b69]">
              Войдите по рабочему e-mail и коду из письма.
            </p>
          </div>
        </div>

        <div
          v-if="telegramMiniAppMode === 'checking' || isMessengerMiniApp"
          class="rounded-[24px] border px-4 py-3 text-sm leading-6"
          :class="telegramMiniAppMode === 'checking'
            ? 'border-[#dce9e1] bg-[#f7fbf9] text-[#355947]'
            : 'border-[#cbe9d6] bg-[#f1fbf5] text-[#1c6b45]'"
        >
          <template v-if="telegramMiniAppMode === 'checking'">
            {{ `Проверяем аккаунт ${resolveMessengerMiniAppLabel()}…` }}
          </template>
          <template v-else>
            {{
              messengerMiniAppDisplayName
                ? `Вы вошли из ${resolveMessengerMiniAppLabel()} как ${messengerMiniAppDisplayName}.`
                : `Вы открыли кабинет внутри ${resolveMessengerMiniAppLabel()}.`
            }}
          </template>
        </div>

        <div v-if="step === 'request'" class="space-y-5">
          <label class="block space-y-2">
            <span class="text-sm font-semibold text-[#355947]">E-mail</span>
            <input
              v-model="email"
              type="email"
              class="input manager-field h-14 w-full px-4 text-base text-[#123824]"
              placeholder="name@company.com"
              @keydown.enter.prevent="requestCode"
            >
          </label>

          <button
            class="btn h-12 w-full rounded-full border-0 bg-[#123824] text-white shadow-[0_16px_32px_rgba(18,56,36,0.18)] hover:bg-[#0f2f20] disabled:border-0 disabled:bg-[#cfd8d2] disabled:text-[#6f8579]"
            :disabled="requestCodeMutation.loading.value || !isEmailReady"
            @click="requestCode"
          >
            {{ requestCodeMutation.loading.value ? 'Отправляем код…' : 'Получить код' }}
          </button>

          <div v-if="hasMessengerButtons" class="space-y-3">
            <div class="flex items-center gap-3">
              <span class="h-px flex-1 bg-[#e2ece6]" />
              <span class="text-[11px] font-bold uppercase tracking-[0.18em] text-[#7a9386]">или войти через</span>
              <span class="h-px flex-1 bg-[#e2ece6]" />
            </div>

            <div class="grid gap-3 sm:grid-cols-2">
              <button
                v-if="canUseTelegramLogin"
                class="btn h-12 rounded-full border border-[#d7e6dc] bg-white text-[#123824] hover:border-[#bed6c7] hover:bg-[#f6fbf8] disabled:border-[#e6ede9] disabled:bg-[#f8fbf9] disabled:text-[#91a79b]"
                :disabled="pendingChannel === 'TELEGRAM' || !isEmailReady"
                @click="startMessengerLogin('TELEGRAM')"
              >
                {{ pendingChannel === 'TELEGRAM' ? 'Открываем Telegram…' : 'Telegram' }}
              </button>

              <button
                v-if="canUseMaxLogin"
                class="btn h-12 rounded-full border border-[#d7e6dc] bg-white text-[#123824] hover:border-[#bed6c7] hover:bg-[#f6fbf8] disabled:border-[#e6ede9] disabled:bg-[#f8fbf9] disabled:text-[#91a79b]"
                :disabled="pendingChannel === 'MAX' || !isEmailReady"
                @click="startMessengerLogin('MAX')"
              >
                {{ pendingChannel === 'MAX' ? 'Открываем Max…' : 'Max' }}
              </button>
            </div>
          </div>
        </div>

        <div v-else class="space-y-5">
          <div class="rounded-[24px] bg-[#f5faf7] px-4 py-3 text-sm text-[#355947]">
            Код отправлен на <span class="font-semibold text-[#123824]">{{ maskedEmail }}</span>
          </div>

          <label class="block space-y-2">
            <span class="text-sm font-semibold text-[#355947]">Код из письма</span>
            <input
              v-model="code"
              type="text"
              maxlength="6"
              class="input manager-field h-14 w-full px-4 text-base tracking-[0.22em] text-[#123824]"
              placeholder="123456"
              @keydown.enter.prevent="verifyCode"
            >
          </label>

          <div class="space-y-3">
            <button
              class="btn h-12 w-full rounded-full border-0 bg-[#123824] text-white shadow-[0_16px_32px_rgba(18,56,36,0.18)] hover:bg-[#0f2f20] disabled:border-0 disabled:bg-[#cfd8d2] disabled:text-[#6f8579]"
              :disabled="verifyCodeMutation.loading.value || !code.trim()"
              @click="verifyCode"
            >
              {{ verifyCodeMutation.loading.value ? 'Проверяем…' : 'Войти' }}
            </button>

            <button
              class="btn h-12 w-full rounded-full border border-[#d7e6dc] bg-white text-[#123824] hover:border-[#bed6c7] hover:bg-[#f6fbf8]"
              @click="returnToRequestStep"
            >
              Изменить e-mail
            </button>
          </div>

          <p class="text-xs text-[#7a9386]">Код действует до {{ expiresAt }}</p>
        </div>

        <div
          v-if="feedback"
          class="rounded-[24px] border px-4 py-3 text-sm leading-6"
          :class="feedbackTone === 'success'
            ? 'border-[#cbe9d6] bg-[#f1fbf5] text-[#1c6b45]'
            : 'border-[#f1d1c7] bg-[#fff3ef] text-[#9d4426]'"
        >
          {{ feedback }}
        </div>
      </div>
    </div>
  </section>
</template>
