'use client';

import { useCallback, useEffect, useState } from 'react';
import { useRouter } from 'next/navigation';
import { Bell, Loader2, Trash2 } from 'lucide-react';
import { useAuth } from '@/components/id/auth-provider';
import { useToast } from '@/components/id/toast-provider';
import { Button } from '@/components/ui/button';
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
import {
  AppNotification,
  fetchNotifications,
  fetchUnreadNotificationCount,
  getApiErrorMessage,
  markAllNotificationsRead,
  markNotificationRead,
  respondFamilyInvite
} from '@/lib/api';
import { useRealtime } from '@/components/notifications/realtime-provider';
import { cn } from '@/lib/utils';

function formatTime(value: string) {
  return new Intl.DateTimeFormat('ru-RU', { hour: '2-digit', minute: '2-digit', day: 'numeric', month: 'short' }).format(
    new Date(value)
  );
}

export function NotificationBell() {
  const router = useRouter();
  const { token, isPinLocked } = useAuth();
  const { showToast } = useToast();
  const { unreadCount, setUnreadCount, subscribe } = useRealtime();
  const [open, setOpen] = useState(false);
  const [items, setItems] = useState<AppNotification[]>([]);
  const [loading, setLoading] = useState(false);
  const [respondingId, setRespondingId] = useState<string | null>(null);

  const load = useCallback(async () => {
    if (!token || isPinLocked) return;
    setLoading(true);
    try {
      const [list, count] = await Promise.all([fetchNotifications(token), fetchUnreadNotificationCount(token)]);
      setItems(list.notifications ?? []);
      setUnreadCount(count.count ?? 0);
    } catch (error) {
      const message = getApiErrorMessage(error, 'Не удалось загрузить уведомления');
      if (message) showToast(message);
    } finally {
      setLoading(false);
    }
  }, [isPinLocked, setUnreadCount, showToast, token]);

  useEffect(() => {
    void load();
  }, [load]);

  useEffect(() => {
    return subscribe((event) => {
      void load();
      if (event.type === 'chat_message' && event.title) {
        showToast(`${event.title}: ${event.message}`);
      }
      if (event.type === 'family_invite') {
        showToast(event.message || 'Новое приглашение в семью');
      }
      if (event.type === 'role_assigned' || event.type === 'role_removed') {
        showToast(event.message || 'Изменение ролей');
      }
    });
  }, [load, showToast, subscribe]);

  async function openItem(item: AppNotification) {
    if (!token) return;
    await markNotificationRead(item.id, token);
    setUnreadCount((count) => Math.max(0, count - 1));
    setItems((current) => current.filter((entry) => entry.id !== item.id));
    let payload: Record<string, unknown> = {};
    try {
      payload = item.payloadJson ? JSON.parse(item.payloadJson) : {};
    } catch {
      payload = {};
    }
    if (payload.groupId) {
      setOpen(false);
      router.push(`/family/${payload.groupId}`);
      return;
    }
    if (item.type === 'role_assigned' || item.type === 'role_removed') {
      setOpen(false);
      router.push('/admin');
    }
  }

  function removeInviteNotification(inviteId: string) {
    setItems((current) => {
      let removedUnread = 0;
      const next = current.filter((item) => {
        if (item.type !== 'family_invite') return true;
        try {
          const payload = item.payloadJson ? JSON.parse(item.payloadJson) as { inviteId?: string } : {};
          if (payload.inviteId === inviteId) {
            if (!item.isRead) removedUnread += 1;
            return false;
          }
        } catch {
          // keep item if payload is malformed
        }
        return true;
      });
      if (removedUnread > 0) {
        setUnreadCount((count) => Math.max(0, count - removedUnread));
      }
      return next;
    });
  }

  async function acceptInvite(inviteId: string) {
    if (!token) return;
    setRespondingId(inviteId);
    try {
      const invite = await respondFamilyInvite(inviteId, true, token);
      removeInviteNotification(inviteId);
      showToast('Вы присоединились к семье');
      setOpen(false);
      router.push(`/family/${invite.groupId}`);
    } catch (error) {
      const message = getApiErrorMessage(error, 'Не удалось принять приглашение');
      if (message) showToast(message);
    } finally {
      setRespondingId(null);
    }
  }

  async function declineInvite(inviteId: string) {
    if (!token) return;
    setRespondingId(inviteId);
    try {
      await respondFamilyInvite(inviteId, false, token);
      removeInviteNotification(inviteId);
      showToast('Приглашение отклонено');
    } catch (error) {
      const message = getApiErrorMessage(error, 'Не удалось отклонить приглашение');
      if (message) showToast(message);
    } finally {
      setRespondingId(null);
    }
  }

  async function markAllRead() {
    if (!token) return;
    await markAllNotificationsRead(token);
    setUnreadCount(0);
    setItems([]);
  }

  return (
    <Popover open={open} onOpenChange={setOpen}>
      <PopoverTrigger asChild>
        <button
          type="button"
          className="relative flex h-11 w-11 items-center justify-center rounded-2xl bg-[#f4f5f8] transition hover:bg-[#eceef4]"
          aria-label="Уведомления"
        >
          <Bell className="h-5 w-5" />
          {unreadCount > 0 ? (
            <span className="absolute -right-1 -top-1 flex h-5 min-w-5 items-center justify-center rounded-full bg-[#3390ec] px-1 text-[10px] font-semibold text-white">
              {unreadCount > 99 ? '99+' : unreadCount}
            </span>
          ) : null}
        </button>
      </PopoverTrigger>
      <PopoverContent align="end" className="w-[360px] rounded-[24px] p-0">
        <div className="flex items-center justify-between border-b border-[#eceef4] px-4 py-3">
          <h3 className="font-semibold">Уведомления</h3>
          <Button variant="ghost" size="sm" className="h-8 gap-1 text-xs" onClick={() => void markAllRead()}>
            <Trash2 className="h-3.5 w-3.5" />
            Очистить все
          </Button>
        </div>
        <div className="max-h-[420px] overflow-y-auto">
          {loading ? (
            <div className="flex items-center justify-center py-10 text-sm text-[#667085]">
              <Loader2 className="mr-2 h-4 w-4 animate-spin" />
              Загрузка...
            </div>
          ) : items.length === 0 ? (
            <p className="px-4 py-10 text-center text-sm text-[#667085]">Уведомлений пока нет</p>
          ) : (
            items.map((item) => {
              let inviteId: string | undefined;
              try {
                inviteId = item.payloadJson ? (JSON.parse(item.payloadJson).inviteId as string) : undefined;
              } catch {
                inviteId = undefined;
              }
              return (
                <div
                  key={item.id}
                  className={cn(
                    'border-b border-[#eceef4] px-4 py-3 transition hover:bg-[#fafbfd]',
                    !item.isRead && 'bg-[#f0f8ff]/60'
                  )}
                >
                  <button type="button" className="w-full text-left" onClick={() => void openItem(item)}>
                    <div className="flex items-start justify-between gap-2">
                      <div>
                        <p className="font-medium">{item.title}</p>
                        <p className="mt-1 text-sm text-[#667085]">{item.message}</p>
                      </div>
                      <span className="shrink-0 text-[11px] text-[#a8adbc]">{formatTime(item.createdAt)}</span>
                    </div>
                  </button>
                  {item.type === 'family_invite' && inviteId ? (
                    <div className="mt-3 flex gap-2">
                      <Button
                        size="sm"
                        className="h-8 flex-1 rounded-xl"
                        disabled={respondingId === inviteId}
                        onClick={() => void acceptInvite(inviteId!)}
                      >
                        {respondingId === inviteId ? <Loader2 className="h-4 w-4 animate-spin" /> : 'Принять'}
                      </Button>
                      <Button
                        size="sm"
                        variant="secondary"
                        className="h-8 flex-1 rounded-xl"
                        onClick={() => void declineInvite(inviteId!)}
                      >
                        Отклонить
                      </Button>
                    </div>
                  ) : null}
                </div>
              );
            })
          )}
        </div>
      </PopoverContent>
    </Popover>
  );
}
