import { createContext, useContext, useRef, useEffect, useCallback, type ReactNode } from 'react';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { useLocation } from 'react-router-dom';
import { toast } from 'sonner';
import { Bell, X } from 'lucide-react';
import api from '@/lib/api';
import { getRelativeTime, toLocalDatetime } from '@/lib/date-utils';
import { useLock } from '@/hooks/useLock';
import SnoozeDropdown from '@/components/reminders/SnoozeDropdown';
import type { Reminder } from '@/types';

const MAX_TOASTS = 3;

interface AlertsContextValue {
  alerts: Reminder[];
  dismiss: (id: number) => void;
  snooze: (id: number, minutes: 5 | 10 | 15) => void;
}

const AlertsContext = createContext<AlertsContextValue>({
  alerts: [],
  dismiss: () => {},
  snooze: () => {},
});

export function useAlerts() {
  return useContext(AlertsContext);
}

export function AlertsProvider({ children }: { children: ReactNode }) {
  const queryClient = useQueryClient();
  const location = useLocation();
  const { isLocked } = useLock();
  const firedRef = useRef<Set<number>>(new Set());
  const prevPathnameRef = useRef(location.pathname);
  const isDashboard = location.pathname === '/' || location.pathname === '/dashboard';

  const { data: alerts = [] } = useQuery<Reminder[]>({
    queryKey: ['reminders', 'due'],
    queryFn: async () => {
      const { data } = await api.get<Reminder[]>('/reminders/due', {
        params: { client_now: toLocalDatetime() },
      });
      return data;
    },
    refetchInterval: 30_000,
    staleTime: 0,
    refetchIntervalInBackground: false,
    refetchOnWindowFocus: true,
  });

  // Prune firedRef — remove IDs no longer in the response
  useEffect(() => {
    const currentIds = new Set(alerts.map((a) => a.id));
    firedRef.current.forEach((id) => {
      if (!currentIds.has(id)) {
        firedRef.current.delete(id);
        toast.dismiss(`reminder-${id}`);
      }
    });
  }, [alerts]);

  const dismissMutation = useMutation({
    mutationFn: (id: number) => api.patch(`/reminders/${id}/dismiss`),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['reminders'] });
      queryClient.invalidateQueries({ queryKey: ['dashboard'] });
    },
    onError: () => {
      queryClient.invalidateQueries({ queryKey: ['reminders', 'due'] });
      toast.error('Failed to dismiss reminder');
    },
  });

  const snoozeMutation = useMutation({
    mutationFn: ({ id, minutes }: { id: number; minutes: 5 | 10 | 15 }) =>
      api.patch(`/reminders/${id}/snooze`, { minutes, client_now: toLocalDatetime() }),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['reminders'] });
      queryClient.invalidateQueries({ queryKey: ['dashboard'] });
    },
    onError: () => {
      queryClient.invalidateQueries({ queryKey: ['reminders', 'due'] });
      toast.error('Failed to snooze reminder');
    },
  });

  const updateSummaryToast = useCallback(() => {
    // Count alerts that are still fired but don't have individual toasts (overflow)
    const totalFired = firedRef.current.size;
    const overflow = totalFired - MAX_TOASTS;
    if (overflow > 0) {
      toast.custom(
        (t) => renderSummaryToast(t, overflow),
        { id: 'reminder-summary', duration: Infinity }
      );
    } else {
      toast.dismiss('reminder-summary');
    }
  }, []);

  const handleDismiss = useCallback((id: number) => {
    toast.dismiss(`reminder-${id}`);
    firedRef.current.delete(id);
    updateSummaryToast();
    dismissMutation.mutate(id);
  }, [dismissMutation, updateSummaryToast]);

  const handleSnooze = useCallback((id: number, minutes: 5 | 10 | 15) => {
    toast.dismiss(`reminder-${id}`);
    firedRef.current.delete(id);
    updateSummaryToast();
    snoozeMutation.mutate({ id, minutes });
  }, [snoozeMutation, updateSummaryToast]);

  // Store latest callbacks in refs so toast closures always call current versions
  const dismissRef = useRef(handleDismiss);
  const snoozeRef = useRef(handleSnooze);
  useEffect(() => { dismissRef.current = handleDismiss; }, [handleDismiss]);
  useEffect(() => { snoozeRef.current = handleSnooze; }, [handleSnooze]);

  function renderToast(_t: string | number, reminder: Reminder) {
    const timeAgo = reminder.remind_at ? getRelativeTime(reminder.remind_at) : '';
    return (
      <div className="flex items-center gap-3 bg-card border border-border rounded-lg p-3 shadow-lg w-[356px]">
        <div className="p-1.5 rounded-md bg-orange-500/10 shrink-0">
          <Bell className="h-4 w-4 text-orange-400" />
        </div>
        <div className="flex-1 min-w-0">
          <p className="text-sm font-medium text-foreground truncate">{reminder.title}</p>
          <p className="text-xs text-muted-foreground mt-0.5">{timeAgo}</p>
        </div>
        <div className="flex items-center gap-1 shrink-0">
          <SnoozeDropdown
            onSnooze={(m) => snoozeRef.current(reminder.id, m)}
            label={reminder.title}
            direction="down"
          />
          <button
            onClick={() => dismissRef.current(reminder.id)}
            aria-label={`Dismiss "${reminder.title}"`}
            className="flex items-center gap-1 px-1.5 py-1 rounded hover:bg-accent/10 hover:text-accent text-muted-foreground transition-colors"
          >
            <X className="h-3.5 w-3.5" />
            <span className="text-[11px] font-medium">Dismiss</span>
          </button>
        </div>
      </div>
    );
  }

  function renderSummaryToast(_t: string | number, count: number) {
    return (
      <div className="flex items-center gap-3 bg-card border border-border rounded-lg p-3 shadow-lg w-[356px]">
        <div className="p-1.5 rounded-md bg-orange-500/10 shrink-0">
          <Bell className="h-4 w-4 text-orange-400" />
        </div>
        <p className="text-sm text-muted-foreground">
          +{count} more reminder{count > 1 ? 's' : ''} due
        </p>
      </div>
    );
  }

  function fireToasts(reminders: Reminder[]) {
    const newAlerts = reminders.filter((a) => !firedRef.current.has(a.id));
    if (newAlerts.length === 0) return;

    const toShow = newAlerts.slice(0, MAX_TOASTS);
    const overflow = newAlerts.length - MAX_TOASTS;

    toShow.forEach((reminder) => {
      firedRef.current.add(reminder.id);
      toast.custom(
        (t) => renderToast(t, reminder),
        { id: `reminder-${reminder.id}`, duration: Infinity }
      );
    });

    // Mark remaining as fired to prevent re-firing
    newAlerts.slice(MAX_TOASTS).forEach((a) => firedRef.current.add(a.id));

    if (overflow > 0) {
      toast.custom(
        (t) => renderSummaryToast(t, overflow),
        { id: 'reminder-summary', duration: Infinity }
      );
    }
  }

  // Unified toast management — single effect handles route changes, lock state, and new alerts
  useEffect(() => {
    const wasOnDashboard = prevPathnameRef.current === '/' || prevPathnameRef.current === '/dashboard';
    const nowOnDashboard = isDashboard;
    prevPathnameRef.current = location.pathname;

    // Suppress toasts while locked — dismiss any visible ones
    if (isLocked) {
      alerts.forEach((a) => toast.dismiss(`reminder-${a.id}`));
      toast.dismiss('reminder-summary');
      firedRef.current.clear();
      return;
    }

    if (nowOnDashboard) {
      // On dashboard — dismiss all toasts, banner takes over
      alerts.forEach((a) => toast.dismiss(`reminder-${a.id}`));
      toast.dismiss('reminder-summary');
      firedRef.current.clear();
      return;
    }

    // Transitioning away from dashboard — reset fired set so all current alerts get toasts
    if (wasOnDashboard && !nowOnDashboard) {
      firedRef.current.clear();
    }

    // On non-dashboard page — fire toasts for any unfired alerts
    fireToasts(alerts);
  }, [location.pathname, isDashboard, alerts, isLocked]);

  return (
    <AlertsContext.Provider value={{ alerts, dismiss: handleDismiss, snooze: handleSnooze }}>
      {children}
    </AlertsContext.Provider>
  );
}
