'use client';

/**
 * Delivery Notification Service
 * 
 * This hook monitors for new deliveries and generates notifications when:
 * - A supplier makes their first delivery to a school
 * - A new delivery is recorded
 * 
 * Notifications are stored in localStorage and displayed via the notification bell.
 */

import { useEffect, useCallback, useRef } from 'react';
import { useQuery, useQueryClient } from '@tanstack/react-query';
import api from '../lib/api-client';

// Types
export interface DeliveryNotification {
  id: string;
  type: 'first_delivery' | 'new_delivery';
  title: string;
  message: string;
  supplierName: string;
  schoolName: string;
  deliveryId: number;
  createdAt: string;
  read: boolean;
}

interface DeliveryRecord {
  id: number;
  supplier_id: number;
  supplier_name: string;
  school_id: number;
  school_name: string;
  commodity_name: string;
  delivery_date: string;
  created_at: string;
}

interface DeliveriesResponse {
  data: DeliveryRecord[];
  pagination: {
    total: number;
    page: number;
    per_page: number;
  };
}

// Constants
const STORAGE_KEY = 'gcx_fshs_notifications';
const SEEN_DELIVERIES_KEY = 'gcx_fshs_seen_deliveries';
const FIRST_DELIVERY_TRACKER_KEY = 'gcx_fshs_supplier_school_deliveries';
const POLL_INTERVAL = 30_000; // Poll every 30 seconds
const MAX_NOTIFICATIONS = 50;

// Helper functions
const getStoredNotifications = (): DeliveryNotification[] => {
  try {
    const raw = localStorage.getItem(STORAGE_KEY);
    if (!raw) return [];
    const parsed = JSON.parse(raw);
    return Array.isArray(parsed) ? parsed : [];
  } catch {
    return [];
  }
};

const saveNotifications = (notifications: DeliveryNotification[]) => {
  try {
    // Keep only the most recent notifications
    const trimmed = notifications.slice(0, MAX_NOTIFICATIONS);
    localStorage.setItem(STORAGE_KEY, JSON.stringify(trimmed));
  } catch {
    // Ignore storage errors
  }
};

const getSeenDeliveryIds = (): Set<number> => {
  try {
    const raw = localStorage.getItem(SEEN_DELIVERIES_KEY);
    if (!raw) return new Set();
    return new Set(JSON.parse(raw));
  } catch {
    return new Set();
  }
};

const saveSeenDeliveryIds = (ids: Set<number>) => {
  try {
    // Keep last 1000 IDs to prevent unbounded growth
    const arr = Array.from(ids).slice(-1000);
    localStorage.setItem(SEEN_DELIVERIES_KEY, JSON.stringify(arr));
  } catch {
    // Ignore storage errors
  }
};

// Track supplier-school pairs that have had deliveries
const getSupplierSchoolPairs = (): Set<string> => {
  try {
    const raw = localStorage.getItem(FIRST_DELIVERY_TRACKER_KEY);
    if (!raw) return new Set();
    return new Set(JSON.parse(raw));
  } catch {
    return new Set();
  }
};

const saveSupplierSchoolPairs = (pairs: Set<string>) => {
  try {
    localStorage.setItem(FIRST_DELIVERY_TRACKER_KEY, JSON.stringify(Array.from(pairs)));
  } catch {
    // Ignore storage errors
  }
};

const makeSupplierSchoolKey = (supplierId: number, schoolId: number): string => 
  `${supplierId}_${schoolId}`;

const generateNotificationId = (): string => 
  `notif_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;

/**
 * Hook to monitor deliveries and generate notifications
 */
export function useDeliveryNotifications(enabled: boolean = true) {
  const queryClient = useQueryClient();
  const lastCheckRef = useRef<string | null>(null);
  
  // Fetch recent deliveries
  const { data: deliveriesData } = useQuery<DeliveriesResponse>({
    queryKey: ['delivery-notifications-check'],
    queryFn: async () => {
      const response = await api.get('/deliveries', {
        params: {
          page: 1,
          per_page: 50,
          sort: 'created_at',
          order: 'desc',
        },
      });
      return response.data;
    },
    enabled,
    refetchInterval: POLL_INTERVAL,
    staleTime: POLL_INTERVAL / 2,
    refetchOnWindowFocus: true,
  });
  
  // Process new deliveries and generate notifications
  const processDeliveries = useCallback((deliveries: DeliveryRecord[]) => {
    const seenIds = getSeenDeliveryIds();
    const supplierSchoolPairs = getSupplierSchoolPairs();
    const currentNotifications = getStoredNotifications();
    
    const newNotifications: DeliveryNotification[] = [];
    let pairsChanged = false;
    let seenChanged = false;
    
    for (const delivery of deliveries) {
      // Skip if we've already seen this delivery
      if (seenIds.has(delivery.id)) continue;
      
      seenIds.add(delivery.id);
      seenChanged = true;
      
      const pairKey = makeSupplierSchoolKey(delivery.supplier_id, delivery.school_id);
      const isFirstDelivery = !supplierSchoolPairs.has(pairKey);
      
      if (isFirstDelivery) {
        // Mark this supplier-school pair as having had a delivery
        supplierSchoolPairs.add(pairKey);
        pairsChanged = true;
        
        // Generate "first delivery" notification
        newNotifications.push({
          id: generateNotificationId(),
          type: 'first_delivery',
          title: '🚚 First Delivery Started!',
          message: `${delivery.supplier_name || 'A supplier'} has started making deliveries to ${delivery.school_name || 'a school'}. Please submit your entries if not already done.`,
          supplierName: delivery.supplier_name || 'Unknown Supplier',
          schoolName: delivery.school_name || 'Unknown School',
          deliveryId: delivery.id,
          createdAt: new Date().toISOString(),
          read: false,
        });
      }
    }
    
    // Save updates
    if (seenChanged) {
      saveSeenDeliveryIds(seenIds);
    }
    
    if (pairsChanged) {
      saveSupplierSchoolPairs(supplierSchoolPairs);
    }
    
    if (newNotifications.length > 0) {
      // Add new notifications at the beginning
      const updated = [...newNotifications, ...currentNotifications];
      saveNotifications(updated);
      
      // Trigger a re-render in components that use notifications
      window.dispatchEvent(new CustomEvent('notifications-updated', { 
        detail: { count: newNotifications.length } 
      }));
      
      // Also show a browser notification if permitted
      if (typeof Notification !== 'undefined' && Notification.permission === 'granted') {
        newNotifications.forEach((notif) => {
          new Notification(notif.title, {
            body: notif.message,
            icon: '/icons/icon-192x192.png',
            tag: notif.id,
          });
        });
      }
    }
    
    return newNotifications;
  }, []);
  
  // Process deliveries when data changes
  useEffect(() => {
    if (!deliveriesData?.data) return;
    
    // Create a fingerprint of the current data to avoid reprocessing
    const fingerprint = deliveriesData.data.map(d => d.id).join(',');
    if (fingerprint === lastCheckRef.current) return;
    lastCheckRef.current = fingerprint;
    
    processDeliveries(deliveriesData.data);
  }, [deliveriesData, processDeliveries]);
  
  // Request notification permission on mount
  useEffect(() => {
    if (typeof Notification !== 'undefined' && Notification.permission === 'default') {
      // Don't auto-request, wait for user interaction
    }
  }, []);
  
  return {
    requestNotificationPermission: async () => {
      if (typeof Notification !== 'undefined' && Notification.permission === 'default') {
        const permission = await Notification.requestPermission();
        return permission === 'granted';
      }
      return Notification?.permission === 'granted';
    },
    
    getNotifications: getStoredNotifications,
    
    markAsRead: (notificationId: string) => {
      const notifications = getStoredNotifications();
      const updated = notifications.map(n => 
        n.id === notificationId ? { ...n, read: true } : n
      );
      saveNotifications(updated);
      window.dispatchEvent(new CustomEvent('notifications-updated'));
    },
    
    markAllAsRead: () => {
      const notifications = getStoredNotifications();
      const updated = notifications.map(n => ({ ...n, read: true }));
      saveNotifications(updated);
      window.dispatchEvent(new CustomEvent('notifications-updated'));
    },
    
    clearNotification: (notificationId: string) => {
      const notifications = getStoredNotifications();
      const updated = notifications.filter(n => n.id !== notificationId);
      saveNotifications(updated);
      window.dispatchEvent(new CustomEvent('notifications-updated'));
    },
    
    clearAllNotifications: () => {
      saveNotifications([]);
      window.dispatchEvent(new CustomEvent('notifications-updated'));
    },
    
    getUnreadCount: () => {
      return getStoredNotifications().filter(n => !n.read).length;
    },
  };
}

/**
 * Hook to subscribe to notification updates
 */
export function useNotificationUpdates(onUpdate?: () => void) {
  useEffect(() => {
    const handler = () => {
      onUpdate?.();
    };
    
    window.addEventListener('notifications-updated', handler);
    return () => window.removeEventListener('notifications-updated', handler);
  }, [onUpdate]);
}

/**
 * Initialize the notification service (call once at app root)
 */
export function useInitDeliveryNotifications() {
  // Initialize the service to start monitoring
  useDeliveryNotifications(true);
  
  // On first load, seed the tracker with existing supplier-school pairs
  // to avoid generating notifications for historical deliveries
  useEffect(() => {
    const initializeTracker = async () => {
      const pairs = getSupplierSchoolPairs();
      
      // If tracker is empty, this is first run - seed it with existing data
      if (pairs.size === 0) {
        try {
          // Fetch a larger batch of historical deliveries to seed the tracker
          const response = await api.get('/deliveries', {
            params: {
              page: 1,
              per_page: 500,
              sort: 'created_at',
              order: 'desc',
            },
          });
          
          const deliveries: DeliveryRecord[] = response.data?.data || [];
          const seenIds = new Set<number>();
          
          for (const delivery of deliveries) {
            const key = makeSupplierSchoolKey(delivery.supplier_id, delivery.school_id);
            pairs.add(key);
            seenIds.add(delivery.id);
          }
          
          saveSupplierSchoolPairs(pairs);
          saveSeenDeliveryIds(seenIds);
          
          console.log(`[DeliveryNotifications] Initialized with ${pairs.size} supplier-school pairs`);
        } catch (error) {
          console.error('[DeliveryNotifications] Failed to initialize tracker:', error);
        }
      }
    };
    
    initializeTracker();
  }, []);
}

export default useDeliveryNotifications;
