'use client';

import { FormEvent, useCallback, useEffect, useMemo, useState } from 'react';
import Link from 'next/link';
import { useParams, useRouter } from 'next/navigation';
import { ArrowLeft, Copy, Eye, Info, Loader2, LockKeyhole, ShieldCheck, StickyNote } from 'lucide-react';
import { useToast } from '@/app/components/ToastProvider';
import { getResponseErrorDetails } from '@/lib/api-client';
import { copyToClipboard } from '@/lib/utils';
import {
  decryptNotebookCiphertext,
  deriveNotebookPasswordVerifier,
} from '@/lib/notebook/crypto';

type PublicNoteMeta = {
  publicId: string;
  title: string | null;
  destroyMode: 'after_reading' | 'expires_at';
  expiresAt: string | null;
  passwordRequired: boolean;
  salt: string;
};

type EncryptedPublicNote = PublicNoteMeta & {
  ciphertext: string;
  iv: string;
};

function getHashSecret() {
  if (typeof window === 'undefined') return '';
  return decodeURIComponent(window.location.hash.replace(/^#/, '').trim());
}

function formatDate(value: string | null) {
  if (!value) return '';
  const date = new Date(value);
  if (Number.isNaN(date.getTime())) return '';

  return date.toLocaleString('ru-RU', {
    day: '2-digit',
    month: 'long',
    year: 'numeric',
    hour: '2-digit',
    minute: '2-digit',
  });
}

async function getResponseMessage(response: Response, fallback: string) {
  const details = await getResponseErrorDetails(response, fallback);
  return details.message;
}

export default function PublicNotebookNotePage() {
  const params = useParams<{ publicId: string }>();
  const router = useRouter();
  const toast = useToast();
  const publicId = params?.publicId || '';

  const [secret, setSecret] = useState('');
  const [note, setNote] = useState<PublicNoteMeta | null>(null);
  const [password, setPassword] = useState('');
  const [revealedText, setRevealedText] = useState('');
  const [showPrivacy, setShowPrivacy] = useState(false);
  const [isLoading, setIsLoading] = useState(true);
  const [isOpening, setIsOpening] = useState(false);
  const [error, setError] = useState('');

  const title = useMemo(() => note?.title?.trim() || 'Секретная записка', [note?.title]);
  const expiryText = useMemo(() => formatDate(note?.expiresAt ?? null), [note?.expiresAt]);

  useEffect(() => {
    setSecret(getHashSecret());
  }, []);

  useEffect(() => {
    if (!publicId) return;

    let cancelled = false;

    const loadNote = async () => {
      setIsLoading(true);
      setError('');

      try {
        const response = await fetch(`/api/notes/${encodeURIComponent(publicId)}`, { cache: 'no-store' });
        if (!response.ok) {
          if (response.status === 404 || response.status === 410) {
            router.replace('/');
            return;
          }
          throw new Error(await getResponseMessage(response, 'Не удалось загрузить записку'));
        }

        const body = await response.json() as { note: PublicNoteMeta };
        if (!cancelled) {
          setNote(body.note);
        }
      } catch (loadError) {
        if (!cancelled) {
          setError(loadError instanceof Error ? loadError.message : 'Не удалось загрузить записку');
        }
      } finally {
        if (!cancelled) {
          setIsLoading(false);
        }
      }
    };

    void loadNote();

    return () => {
      cancelled = true;
    };
  }, [publicId, router]);

  const handleOpen = useCallback(async (event?: FormEvent) => {
    event?.preventDefault();
    if (!note || isOpening) return;

    const currentSecret = secret || getHashSecret();
    if (!currentSecret) {
      setError('В ссылке нет ключа расшифровки после #');
      return;
    }

    const passwordValue = password.trim();
    if (note.passwordRequired && !passwordValue) {
      setError('Введите пароль записки');
      return;
    }

    setIsOpening(true);
    setError('');

    try {
      const passwordVerifier = note.passwordRequired
        ? await deriveNotebookPasswordVerifier({
          secret: currentSecret,
          password: passwordValue,
          salt: note.salt,
        })
        : null;

      const response = await fetch(`/api/notes/${encodeURIComponent(note.publicId)}`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ passwordVerifier }),
      });

      if (!response.ok) {
        if (response.status === 404 || response.status === 410) {
          router.replace('/');
          return;
        }
        throw new Error(await getResponseMessage(response, 'Не удалось открыть записку'));
      }

      const body = await response.json() as { note: EncryptedPublicNote };
      const plainText = await decryptNotebookCiphertext({
        ciphertext: body.note.ciphertext,
        iv: body.note.iv,
        salt: body.note.salt,
        secret: currentSecret,
        password: passwordValue,
      });
      setRevealedText(plainText);
      setNote(body.note);
    } catch (openError) {
      setError(openError instanceof Error ? openError.message : 'Не удалось открыть записку');
    } finally {
      setIsOpening(false);
    }
  }, [isOpening, note, password, router, secret]);

  const handleCopyRevealedText = useCallback(async () => {
    if (!revealedText) return;
    const copied = await copyToClipboard(revealedText);
    if (copied) {
      toast.success('Текст скопирован');
    }
  }, [revealedText, toast]);

  return (
    <div className="relative min-h-screen overflow-hidden bg-[#050505] px-4 py-10 text-white">
      <div className="pointer-events-none absolute inset-0 bg-[radial-gradient(circle_at_top_right,_rgba(139,92,246,0.16),_transparent_52%)]" />

      <main className="relative z-10 mx-auto flex min-h-[calc(100vh-5rem)] w-full max-w-2xl items-center">
        <div className="w-full rounded-2xl border border-white/10 bg-black/45 p-5 shadow-[0_24px_80px_rgba(0,0,0,0.6)] backdrop-blur-xl md:p-8">
          <Link href="/" className="mb-6 inline-flex items-center gap-2 text-sm text-gray-500 transition-colors hover:text-white">
            <ArrowLeft className="h-4 w-4" />
            На главную
          </Link>

          {isLoading ? (
            <div className="flex min-h-[260px] items-center justify-center text-sm text-gray-400">
              <Loader2 className="mr-2 h-5 w-5 animate-spin text-violet-300" />
              Загрузка записки...
            </div>
          ) : revealedText ? (
            <div>
              <div className="mb-5 text-center">
                <div className="mx-auto mb-4 inline-flex h-12 w-12 items-center justify-center rounded-xl border border-violet-500/30 bg-violet-500/15 text-violet-200">
                  <StickyNote className="h-6 w-6" />
                </div>
                <h1 className="text-2xl font-semibold tracking-tight text-white">{title}</h1>
                {note?.destroyMode === 'after_reading' ? (
                  <p className="mt-2 text-sm text-amber-200">Эта записка уничтожена после раскрытия.</p>
                ) : expiryText ? (
                  <p className="mt-2 text-sm text-gray-500">Записка доступна до {expiryText}.</p>
                ) : note?.destroyMode === 'expires_at' ? (
                  <p className="mt-2 text-sm text-gray-500">Записка доступна навсегда.</p>
                ) : null}
              </div>
              <pre className="max-h-[60vh] overflow-auto whitespace-pre-wrap break-words rounded-2xl border border-violet-500/20 bg-black/40 p-4 font-mono text-sm leading-relaxed text-gray-100 shadow-[inset_0_0_28px_rgba(139,92,246,0.08)]">
                {revealedText}
              </pre>
              <div className="mt-4 flex justify-center">
                <button
                  type="button"
                  onClick={() => void handleCopyRevealedText()}
                  className="inline-flex h-10 items-center justify-center gap-2 rounded-lg border border-white/10 bg-white/[0.03] px-4 text-sm text-gray-300 transition-colors hover:bg-white/[0.08] hover:text-white"
                >
                  <Copy className="h-4 w-4" />
                  Скопировать
                </button>
              </div>
            </div>
          ) : note ? (
            <form onSubmit={handleOpen}>
              <div className="mb-6 text-center">
                <div className="mx-auto mb-4 inline-flex h-12 w-12 items-center justify-center rounded-xl border border-violet-500/30 bg-violet-500/15 text-violet-200">
                  <StickyNote className="h-6 w-6" />
                </div>
                <h1 className="mb-2 text-2xl font-semibold tracking-tight text-white">{title}</h1>
                <p className="mx-auto max-w-md text-sm leading-relaxed text-gray-400">
                  {note.destroyMode === 'after_reading'
                    ? 'После нажатия записка будет показана один раз и сразу уничтожена.'
                    : expiryText
                      ? `Записка доступна до ${expiryText}.`
                      : 'Записка доступна навсегда.'}
                </p>
              </div>

              {note.passwordRequired ? (
                <div className="mx-auto mb-4 max-w-md">
                  <label htmlFor="notebook-note-password" className="mb-2 flex items-center justify-center gap-2 text-center text-sm font-medium text-gray-300">
                    <LockKeyhole className="h-4 w-4 text-violet-300" />
                    Пароль записки
                  </label>
                  <input
                    id="notebook-note-password"
                    type="password"
                    value={password}
                    onChange={(event) => setPassword(event.target.value)}
                    className="h-12 w-full rounded-xl border border-white/10 bg-white/[0.03] px-4 text-center text-white outline-none transition-colors placeholder:text-center placeholder:text-gray-500 focus:border-violet-500/45"
                    placeholder="Введите пароль"
                  />
                </div>
              ) : null}

              {error ? (
                <p className="mb-4 rounded-lg border border-red-500/20 bg-red-500/10 px-3 py-2 text-sm text-red-200">
                  {error}
                </p>
              ) : null}

              <div className="mx-auto max-w-md">
                <button
                  type="submit"
                  disabled={isOpening}
                  className="inline-flex h-12 w-full items-center justify-center gap-2 rounded-xl bg-gradient-to-r from-fuchsia-500 to-violet-600 text-sm font-semibold text-white transition-all duration-200 hover:opacity-95 disabled:cursor-not-allowed disabled:opacity-70"
                >
                  {isOpening ? (
                    <>
                      <Loader2 className="h-4 w-4 animate-spin" />
                      Открытие...
                    </>
                  ) : (
                    <>
                      <Eye className="h-4 w-4" />
                      Показать записку
                    </>
                  )}
                </button>
              </div>
            </form>
          ) : (
            <div>
              <h1 className="mb-3 text-2xl font-semibold tracking-tight text-white">Записка недоступна</h1>
              {error ? <p className="text-sm text-gray-500">{error}</p> : null}
            </div>
          )}

          <div className="mt-6 border-t border-white/10 pt-4 text-center">
            <button
              type="button"
              onClick={() => setShowPrivacy((value) => !value)}
              className="inline-flex items-center justify-center gap-2 text-xs text-gray-600 transition-colors hover:text-gray-300"
            >
              <ShieldCheck className="h-3.5 w-3.5" />
              О конфиденциальности
            </button>
            {showPrivacy ? (
              <div className="mx-auto mt-3 max-w-xl rounded-xl border border-white/10 bg-white/[0.02] p-3 text-center text-xs leading-relaxed text-gray-500">
                <p className="mb-2 flex items-center justify-center gap-2 text-center text-gray-400">
                  <Info className="h-3.5 w-3.5 text-violet-300" />
                  Текст расшифровывается в браузере по ключу из ссылки.
                </p>
                <p>Сервер хранит зашифрованный текст. Одноразовые записки уничтожаются после раскрытия, временные доступны только до выбранного срока.</p>
              </div>
            ) : null}
          </div>
        </div>
      </main>
    </div>
  );
}
