'use client';

import { Suspense, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import Link from 'next/link';
import { useRouter, useSearchParams } from 'next/navigation';
import { CheckCircle2, Loader2, ShieldCheck } from 'lucide-react';
import { BrandLogo } from '@/components/id/brand-logo';
import { useAuth } from '@/components/id/auth-provider';
import { usePublicSettings } from '@/components/id/public-settings-provider';
import { Button } from '@/components/ui/button';
import {
  approveOAuthAuthorization,
  checkOAuthConsent,
  fetchAuthSession,
  fetchOAuthClientPublicInfo,
  type OAuthConsentCheckResponse
} from '@/lib/api';

function buildOAuthQuery(searchParams: URLSearchParams) {
  const params = new URLSearchParams();
  searchParams.forEach((value, key) => {
    if (key !== 'userId') params.set(key, value);
  });
  return params;
}

function OAuthAuthorizeContent() {
  const searchParams = useSearchParams();
  const router = useRouter();
  const { user, token, isPinLocked, isLoading } = useAuth();
  const { projectName } = usePublicSettings();
  const [submitting, setSubmitting] = useState(false);
  const [checkingConsent, setCheckingConsent] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [sessionChecked, setSessionChecked] = useState(false);
  const [consentInfo, setConsentInfo] = useState<OAuthConsentCheckResponse | null>(null);
  const [clientName, setClientName] = useState<string | null>(null);
  const autoApproveStartedRef = useRef(false);

  const oauthQuery = useMemo(() => buildOAuthQuery(searchParams), [searchParams]);

  const clientId = searchParams.get('client_id') ?? searchParams.get('clientId');
  const redirectUri = searchParams.get('redirect_uri') ?? searchParams.get('redirectUri');
  const scope = searchParams.get('scope') ?? 'openid profile';
  const state = searchParams.get('state');

  const returnUrl = useMemo(() => `/auth/oauth/authorize?${oauthQuery.toString()}`, [oauthQuery]);

  const clientLabel = clientName ?? consentInfo?.client?.name ?? 'Приложение';

  useEffect(() => {
    if (!clientId) return;
    let cancelled = false;
    void fetchOAuthClientPublicInfo(clientId)
      .then((info) => {
        if (!cancelled && info.name.trim()) {
          setClientName(info.name.trim());
        }
      })
      .catch(() => undefined);
    return () => {
      cancelled = true;
    };
  }, [clientId]);

  useEffect(() => {
    if (!searchParams.has('userId')) return;
    router.replace(returnUrl);
  }, [returnUrl, router, searchParams]);

  useEffect(() => {
    if (isLoading) return;
    if (!clientId || !redirectUri) return;
    if (isPinLocked) return;
    if (user && token) return;
    router.replace(`/auth/login?redirect=${encodeURIComponent(returnUrl)}`);
  }, [clientId, isLoading, isPinLocked, redirectUri, returnUrl, router, token, user]);

  useEffect(() => {
    if (isLoading || isPinLocked || !token || !user) {
      setSessionChecked(false);
      return;
    }

    let cancelled = false;
    void fetchAuthSession(token)
      .then(() => {
        if (!cancelled) setSessionChecked(true);
      })
      .catch(() => {
        if (!cancelled) {
          setSessionChecked(false);
          router.replace(`/auth/login?redirect=${encodeURIComponent(returnUrl)}`);
        }
      });

    return () => {
      cancelled = true;
    };
  }, [isLoading, isPinLocked, returnUrl, router, token, user]);

  const approve = useCallback(async () => {
    if (!token || !user || isPinLocked) return;
    setSubmitting(true);
    setError(null);
    try {
      const data = await approveOAuthAuthorization(oauthQuery, token);
      if (!data.redirectUrl) {
        throw new Error('Сервер не вернул redirect URL');
      }
      window.location.href = data.redirectUrl;
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Ошибка OAuth авторизации');
      autoApproveStartedRef.current = false;
    } finally {
      setSubmitting(false);
    }
  }, [isPinLocked, oauthQuery, token, user]);

  useEffect(() => {
    if (!token || !clientId || !sessionChecked || isPinLocked) return;

    let cancelled = false;
    setCheckingConsent(true);
    void checkOAuthConsent(oauthQuery, token)
      .then((result) => {
        if (cancelled) return;
        setConsentInfo(result);
        if (result.client?.name?.trim()) {
          setClientName(result.client.name.trim());
        }
        if (result.granted && !autoApproveStartedRef.current) {
          autoApproveStartedRef.current = true;
          void approve();
        }
      })
      .catch((err) => {
        if (!cancelled) {
          setError(err instanceof Error ? err.message : 'Не удалось проверить согласие');
        }
      })
      .finally(() => {
        if (!cancelled) setCheckingConsent(false);
      });

    return () => {
      cancelled = true;
    };
  }, [approve, clientId, isPinLocked, oauthQuery, sessionChecked, token]);

  const cancel = useCallback(() => {
    if (!redirectUri) {
      router.push('/');
      return;
    }
    try {
      const url = new URL(redirectUri);
      url.searchParams.set('error', 'access_denied');
      url.searchParams.set('error_description', 'Пользователь отклонил запрос');
      if (state) url.searchParams.set('state', state);
      window.location.href = url.toString();
    } catch {
      router.push('/');
    }
  }, [redirectUri, router, state]);

  const authReady = Boolean(user && token && !isPinLocked && sessionChecked);
  const scopeItems = consentInfo?.requestedScopes ?? [];

  if (isLoading || (clientId && redirectUri && !authReady && !isPinLocked)) {
    return (
      <div className="flex min-h-[60vh] items-center justify-center">
        <Loader2 className="h-6 w-6 animate-spin text-[#667085]" />
      </div>
    );
  }

  if (isPinLocked) {
    return (
      <div className="flex min-h-[60vh] items-center justify-center px-4 text-center">
        <p className="text-sm text-[#667085]">Подтвердите PIN-код, чтобы продолжить авторизацию приложения.</p>
      </div>
    );
  }

  if (!clientId || !redirectUri) {
    return (
      <div className="mx-auto max-w-md px-4 py-16 text-center">
        <h1 className="text-xl font-semibold">Некорректный OAuth запрос</h1>
        <p className="mt-3 text-sm text-[#667085]">Отсутствуют обязательные параметры client_id и redirect_uri.</p>
        <Link href="/" className="mt-6 inline-block text-[#3390ec] hover:underline">
          На главную
        </Link>
      </div>
    );
  }

  if (checkingConsent || (consentInfo?.granted && submitting)) {
    return (
      <div className="flex min-h-[60vh] flex-col items-center justify-center gap-3 px-4 text-center">
        <Loader2 className="h-6 w-6 animate-spin text-[#667085]" />
        <p className="text-sm text-[#667085]">Продолжаем вход в {clientLabel}…</p>
      </div>
    );
  }

  return (
    <div className="mx-auto flex min-h-[70vh] max-w-lg flex-col justify-center px-4 py-12">
      <div className="mb-8 flex justify-center">
        <BrandLogo />
      </div>
      <div className="rounded-[24px] border border-[#eceef4] bg-white p-6 shadow-sm">
        <div className="mb-4 flex h-12 w-12 items-center justify-center rounded-2xl bg-[#eef4ff] text-[#3390ec]">
          <ShieldCheck className="h-6 w-6" />
        </div>
        <h1 className="text-2xl font-semibold">Разрешить доступ?</h1>
        <p className="mt-2 text-sm leading-relaxed text-[#667085]">
          Приложение <span className="font-medium text-[#1f2430]">{clientLabel}</span> запрашивает доступ к данным вашего аккаунта {projectName}.
        </p>
        <div className="mt-4 space-y-3 rounded-2xl bg-[#f4f5f8] p-4 text-sm">
          <p>
            <span className="text-[#667085]">Пользователь:</span> {user?.displayName}
          </p>
          <div>
            <p className="text-[#667085]">Запрашиваемые данные:</p>
            <ul className="mt-2 space-y-2">
              {scopeItems.length > 0 ? (
                scopeItems.map((item) => (
                  <li key={item.slug} className="flex items-start gap-2">
                    <CheckCircle2 className="mt-0.5 h-4 w-4 shrink-0 text-[#3390ec]" />
                    <div>
                      <div className="font-medium text-[#1f2430]">{item.name}</div>
                      {item.description ? <div className="text-xs text-[#667085]">{item.description}</div> : null}
                    </div>
                  </li>
                ))
              ) : (
                <li className="text-[#667085]">{scope}</li>
              )}
            </ul>
          </div>
        </div>
        <p className="mt-4 text-xs leading-relaxed text-[#667085]">
          После подтверждения доступ сохранится, и повторно спрашивать не будем. Отозвать его можно в разделе «Данные → Доступы к данным».
        </p>
        {error ? <p className="mt-4 text-sm text-red-600">{error}</p> : null}
        <div className="mt-6 flex flex-col gap-3 sm:flex-row">
          <Button className="flex-1 rounded-xl" disabled={submitting || !authReady} onClick={() => void approve()}>
            {submitting ? <Loader2 className="mr-2 h-4 w-4 animate-spin" /> : null}
            Разрешить
          </Button>
          <Button variant="outline" className="flex-1 rounded-xl" disabled={submitting} onClick={cancel}>
            Отмена
          </Button>
        </div>
      </div>
    </div>
  );
}

export default function OAuthAuthorizePage() {
  return (
    <Suspense
      fallback={
        <div className="flex min-h-[60vh] items-center justify-center">
          <Loader2 className="h-6 w-6 animate-spin text-[#667085]" />
        </div>
      }
    >
      <OAuthAuthorizeContent />
    </Suspense>
  );
}
