'use client';

/**
 * Unified Inbox - merges the previous AlertBell + NotificationBell into
 * a single bell with two tabs:
 *
 *   System    - port-wide operational alerts (system-generated, all
 *               users with `view_alerts` see the same list). Sourced from
 *               `useAlertList('open')` + `useAlertCount()`.
 *
 *   Personal  - per-user notifications (you signed something, someone
 *               @-mentioned you, your reminder fired, etc.). Sourced from
 *               `useNotifications` + the /api/v1/notifications endpoint.
 *
 * The bell icon shows a single combined unread count. The popover opens
 * to whichever tab has unread items first; ties → Personal.
 *
 * Replaces the topbar's `<AlertBell />` + `<NotificationBell />`. The two
 * old components stay in the tree (untouched) so anything that imports
 * them directly (tests, deep-link pages) keeps working - they're simply
 * no longer mounted in the topbar.
 */

import { useEffect, useMemo, useRef, useState } from 'react';
import Link from 'next/link';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { Bell, ShieldAlert, Inbox as InboxIcon } from 'lucide-react';

import { Button } from '@/components/ui/button';
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
import { ScrollArea } from '@/components/ui/scroll-area';
import { Separator } from '@/components/ui/separator';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
import { apiFetch } from '@/lib/api/client';
import { useUIStore } from '@/stores/ui-store';
import { cn } from '@/lib/utils';
import { useNotifications } from '@/hooks/use-notifications';
import { NotificationItem } from '@/components/notifications/notification-item';
import { AlertCard, AlertCardEmpty } from '@/components/alerts/alert-card';
import { useAlertCount, useAlertList, useAlertRealtime } from '@/components/alerts/use-alerts';

interface NotificationListResponse {
  data: Array<{
    id: string;
    type: string;
    title: string;
    description: string | null;
    link: string | null;
    isRead: boolean;
    createdAt: Date;
  }>;
  total: number;
}

type TabKey = 'personal' | 'system';

export function Inbox() {
  const portSlug = useUIStore((s) => s.currentPortSlug);
  const [open, setOpen] = useState(false);

  // ── System (alerts) ──
  const { data: alertCount } = useAlertCount();
  const { data: alertList, isLoading: alertsLoading } = useAlertList('open', open);
  useAlertRealtime();
  const systemTotal = alertCount?.total ?? 0;
  const systemCritical = alertCount?.bySeverity.critical ?? 0;
  const systemAlerts = alertList?.data ?? [];
  const systemTop = systemAlerts.slice(0, 8);

  // ── Personal (notifications) ──
  const { unreadCount: personalUnread } = useNotifications();
  const queryClient = useQueryClient();
  const { data: notifData, isLoading: notifLoading } = useQuery<NotificationListResponse>({
    queryKey: ['notifications', 'list'],
    queryFn: () => apiFetch('/api/v1/notifications?limit=20'),
    staleTime: 30_000,
    // Only fetch the list when the popover opens - count stays live in the
    // background via useNotifications' realtime hook.
    enabled: open,
  });
  const notifications = notifData?.data ?? [];

  const markRead = useMutation({
    mutationFn: (id: string) => apiFetch(`/api/v1/notifications/${id}`, { method: 'PATCH' }),
    onSuccess: () => queryClient.invalidateQueries({ queryKey: ['notifications'] }),
  });
  const markAllRead = useMutation({
    mutationFn: () => apiFetch('/api/v1/notifications/read-all', { method: 'POST' }),
    onSuccess: () => queryClient.invalidateQueries({ queryKey: ['notifications'] }),
  });

  // ── Combined badge + initial tab ──
  const combined = systemTotal + personalUnread;
  const initialTab = useMemo<TabKey>(() => {
    // Default to whichever side has unread items; tie → Personal (most users
    // care about their own pings before system-wide rumblings).
    if (systemTotal > 0 && personalUnread === 0) return 'system';
    return 'personal';
  }, [systemTotal, personalUnread]);

  const [activeTab, setActiveTab] = useState<TabKey>(initialTab);

  // Re-anchor to the unread side ONLY on the rising edge of `open` (i.e.
  // when the popover actually opens). The previous version ran whenever
  // `initialTab` changed too, which yanked the tab out from under the
  // user any time a new socket event re-derived the initial tab while
  // they were actively reading the other one.
  const initialTabRef = useRef(initialTab);
  useEffect(() => {
    initialTabRef.current = initialTab;
  });
  useEffect(() => {
    if (open) setActiveTab(initialTabRef.current);
  }, [open]);

  return (
    <Popover open={open} onOpenChange={setOpen}>
      <PopoverTrigger asChild>
        <Button
          variant="ghost"
          size="icon"
          className="relative"
          aria-label={`Inbox${combined > 0 ? ` (${combined} unread)` : ''}`}
          data-testid="inbox-bell"
        >
          <InboxIcon className="h-5 w-5" aria-hidden />
          {combined > 0 ? (
            <span
              key={combined}
              data-testid="inbox-bell-badge"
              className={cn(
                'absolute -top-0.5 -right-0.5 flex h-4 min-w-4 items-center justify-center rounded-full px-1 text-xs font-bold text-white shadow-sm ring-2 ring-background animate-badge-pop',
                // Critical system alerts win the colour war - they need the
                // most attention. Otherwise the brand gradient.
                systemCritical > 0 ? 'bg-destructive' : 'bg-gradient-brand',
              )}
            >
              {combined > 99 ? '99+' : combined}
            </span>
          ) : null}
        </Button>
      </PopoverTrigger>

      <PopoverContent align="end" className="w-96 p-0">
        <Tabs value={activeTab} onValueChange={(v) => setActiveTab(v as TabKey)}>
          <div className="flex items-center justify-between px-3 pt-3">
            <TabsList className="h-8 grid grid-cols-2 w-full">
              <TabsTrigger value="personal" className="text-xs gap-1.5">
                <Bell className="h-3 w-3" aria-hidden />
                Personal
                {personalUnread > 0 ? (
                  <span className="ml-1 rounded-full bg-brand/15 px-1.5 text-xs font-semibold text-brand">
                    {personalUnread > 99 ? '99+' : personalUnread}
                  </span>
                ) : null}
              </TabsTrigger>
              <TabsTrigger value="system" className="text-xs gap-1.5">
                <ShieldAlert className="h-3 w-3" aria-hidden />
                System
                {systemTotal > 0 ? (
                  <span
                    className={cn(
                      'ml-1 rounded-full px-1.5 text-xs font-semibold',
                      systemCritical > 0
                        ? 'bg-destructive/15 text-destructive'
                        : 'bg-amber-500/15 text-amber-600',
                    )}
                  >
                    {systemTotal > 99 ? '99+' : systemTotal}
                  </span>
                ) : null}
              </TabsTrigger>
            </TabsList>
          </div>

          {/* ── Personal tab ── */}
          <TabsContent value="personal" className="m-0">
            <div className="flex items-center justify-between px-4 py-2">
              <h4 className="text-xs font-medium uppercase tracking-wide text-muted-foreground">
                Your notifications
              </h4>
              {personalUnread > 0 ? (
                <Button
                  variant="ghost"
                  size="sm"
                  className="h-auto p-0 text-xs text-muted-foreground hover:text-foreground"
                  onClick={() => markAllRead.mutate()}
                  disabled={markAllRead.isPending}
                >
                  Mark all read
                </Button>
              ) : (
                <Link
                  /* eslint-disable-next-line @typescript-eslint/no-explicit-any */
                  href={(portSlug ? `/${portSlug}/notifications` : '/notifications') as any}
                  className="text-xs text-muted-foreground hover:text-foreground"
                >
                  View all
                </Link>
              )}
            </div>
            <Separator />
            <ScrollArea className="max-h-[400px]">
              {notifLoading ? (
                <div className="flex items-center justify-center py-8 text-sm text-muted-foreground">
                  Loading…
                </div>
              ) : notifications.length === 0 ? (
                <div className="flex flex-col items-center justify-center py-10 text-sm text-muted-foreground">
                  <Bell className="mb-2 h-8 w-8 opacity-30" aria-hidden />
                  No notifications
                </div>
              ) : (
                <div className="divide-y">
                  {notifications.map((n) => (
                    <NotificationItem
                      key={n.id}
                      notification={n}
                      onMarkRead={(id) => markRead.mutate(id)}
                    />
                  ))}
                </div>
              )}
            </ScrollArea>
          </TabsContent>

          {/* ── System tab ── */}
          <TabsContent value="system" className="m-0">
            <div className="flex items-center justify-between px-4 py-2">
              <h4 className="text-xs font-medium uppercase tracking-wide text-muted-foreground">
                Active alerts
              </h4>
              <Link
                /* eslint-disable-next-line @typescript-eslint/no-explicit-any */
                href={portSlug ? (`/${portSlug}/alerts` as any) : ('/alerts' as any)}
                className="text-xs text-muted-foreground hover:text-foreground"
              >
                View all
              </Link>
            </div>
            <Separator />
            <ScrollArea className="max-h-[400px]">
              {alertsLoading ? (
                <div className="px-4 py-8 text-center text-sm text-muted-foreground">Loading…</div>
              ) : systemTop.length === 0 ? (
                <div className="p-3">
                  <AlertCardEmpty />
                </div>
              ) : (
                <div className="space-y-2 p-3">
                  {systemTop.map((a) => (
                    <AlertCard key={a.id} alert={a} />
                  ))}
                </div>
              )}
            </ScrollArea>
          </TabsContent>
        </Tabs>
      </PopoverContent>
    </Popover>
  );
}
