"use client";

import React, { createContext, useContext, useState, useEffect, useRef, ReactNode } from "react";
import { clientFetch } from "@/lib/api";
import { toast } from "sonner";
import { getCookie } from "@/lib/api";
import { cacheUtils } from '@/lib/api-client';
import { Package } from "lucide-react";

interface Order {
  _id: string;
  orderId: string;
  status: string;
  totalPrice: number;
  orderDate: string;
  underpaid?: boolean;
  underpaymentAmount?: number;
}

interface UnreadCounts {
  totalUnread: number;
  chatCounts: Record<string, number>;
}

interface NotificationContextType {
  // Chat notifications
  unreadCounts: UnreadCounts;
  chatMetadata: Record<string, { buyerId: string }>;
  
  // Order notifications
  newOrders: Order[];
  clearOrderNotifications: () => void;
  
  // Shared state
  totalNotifications: number;
  loading: boolean;
}

const NotificationContext = createContext<NotificationContextType | undefined>(undefined);

const STORAGE_KEYS = {
  SEEN_ORDER_IDS: 'ember-notifications-seen-orders',
  NEW_ORDERS: 'ember-notifications-new-orders',
  LAST_CHAT_CHECK: 'ember-notifications-last-chat-check'
};

interface NotificationProviderProps {
  children: ReactNode;
}

export function NotificationProvider({ children }: NotificationProviderProps) {
  // Chat notification state
  const [unreadCounts, setUnreadCounts] = useState<UnreadCounts>({ totalUnread: 0, chatCounts: {} });
  const [previousUnreadTotal, setPreviousUnreadTotal] = useState<number>(0);
  const [chatMetadata, setChatMetadata] = useState<Record<string, { buyerId: string }>>({});
  
  // Order notification state
  const [newOrders, setNewOrders] = useState<Order[]>([]);
  const seenOrderIds = useRef<Set<string>>(new Set());
  const isInitialOrdersFetch = useRef(true);
  
  // Shared state
  const [loading, setLoading] = useState(true);
  const audioRef = useRef<HTMLAudioElement | null>(null);
  const vendorIdRef = useRef<string | null>(null);

  // Total notifications count
  const totalNotifications = unreadCounts.totalUnread + newOrders.length;

  // Initialize localStorage and audio
  useEffect(() => {
    // Load seen order IDs from localStorage
    const savedSeenOrders = localStorage.getItem(STORAGE_KEYS.SEEN_ORDER_IDS);
    if (savedSeenOrders) {
      try {
        const orderIds = JSON.parse(savedSeenOrders);
        seenOrderIds.current = new Set(orderIds);
      } catch (error) {
        console.error('Error loading seen order IDs from localStorage:', error);
      }
    }

    // Load new orders from localStorage
    const savedNewOrders = localStorage.getItem(STORAGE_KEYS.NEW_ORDERS);
    if (savedNewOrders) {
      try {
        const orders = JSON.parse(savedNewOrders);
        setNewOrders(orders);
      } catch (error) {
        console.error('Error loading new orders from localStorage:', error);
      }
    }

    // Initialize audio
    audioRef.current = new Audio('/notification.mp3');
    audioRef.current.addEventListener('error', () => {
      audioRef.current = null;
    });

    return () => {
      if (audioRef.current) {
        audioRef.current = null;
      }
    };
  }, []);

  // Save seen order IDs to localStorage whenever it changes
  const updateSeenOrderIds = (orderIds: Set<string>) => {
    seenOrderIds.current = orderIds;
    localStorage.setItem(STORAGE_KEYS.SEEN_ORDER_IDS, JSON.stringify(Array.from(orderIds)));
  };

  // Save new orders to localStorage whenever it changes
  useEffect(() => {
    localStorage.setItem(STORAGE_KEYS.NEW_ORDERS, JSON.stringify(newOrders));
  }, [newOrders]);

  // Get vendor ID from JWT token
  const getVendorIdFromToken = () => {
    if (vendorIdRef.current) {
      return vendorIdRef.current;
    }

    const authToken = getCookie("Authorization") || "";
    
    if (!authToken) {
      throw new Error("No auth token found");
    }
    
    const tokenParts = authToken.split(".");
    if (tokenParts.length !== 3) {
      throw new Error("Invalid token format");
    }
    
    const payload = JSON.parse(atob(tokenParts[1]));
    const vendorId = payload.id;
    
    if (!vendorId) {
      throw new Error("Vendor ID not found in token");
    }

    vendorIdRef.current = vendorId;
    return vendorId;
  };
  
  // Function to play notification sound
  const playNotificationSound = () => {
    if (audioRef.current) {
      audioRef.current.currentTime = 0;
      audioRef.current.play().catch(err => {
        console.log('Error playing sound:', err);
        // Fallback beep if audio file fails
        try {
          const context = new (window.AudioContext || (window as any).webkitAudioContext)();
          const oscillator = context.createOscillator();
          oscillator.type = 'sine';
          oscillator.frequency.setValueAtTime(800, context.currentTime);
          oscillator.connect(context.destination);
          oscillator.start();
          oscillator.stop(context.currentTime + 0.2);
        } catch (e) {
          console.error('Could not play fallback audio', e);
        }
      });
    }
  };

  // Check for new paid orders
  useEffect(() => {
    // Only run this on dashboard pages, but not on admin pages
    if (typeof window === 'undefined' || !window.location.pathname.includes("/dashboard") || window.location.pathname.includes("/dashboard/admin")) return;

    const checkForNewOrders = async () => {
      try {
        // Get orders from the last 24 hours with a more efficient query
        const yesterday = new Date();
        yesterday.setDate(yesterday.getDate() - 1);
        const timestamp = yesterday.toISOString();
        
        const orderData = await clientFetch(`/orders?status=paid&limit=10&orderDate[gte]=${timestamp}`);
        const orders: Order[] = orderData.orders || [];

        // Filter out orders that are still showing as underpaid (cache issue)
        const validPaidOrders = orders.filter(order => {
          // Only include orders that are actually fully paid (not underpaid)
          return order.status === 'paid' && 
                 (!order.underpaid || order.underpaymentAmount === 0);
        });

        // If this is the first fetch, just store the orders without notifications
        if (isInitialOrdersFetch.current) {
          const orderIds = new Set([...seenOrderIds.current, ...validPaidOrders.map(order => order._id)]);
          updateSeenOrderIds(orderIds);
          isInitialOrdersFetch.current = false;
          return;
        }

        // Check for new paid orders that haven't been seen before
        const latestNewOrders = validPaidOrders.filter(order => !seenOrderIds.current.has(order._id));
        
        // Show notifications for new orders
        if (latestNewOrders.length > 0) {
          // Update the seen orders set
          const updatedSeenOrders = new Set([...seenOrderIds.current, ...latestNewOrders.map(order => order._id)]);
          updateSeenOrderIds(updatedSeenOrders);
          
          // Show a toast notification for each new order
          latestNewOrders.forEach(order => {
            toast.success(
              <div className="flex flex-col">
                <p className="font-semibold">New Paid Order!</p>
                <p className="text-sm">Order #{order.orderId}</p>
                <p className="text-sm font-semibold">£{order.totalPrice.toFixed(2)}</p>
              </div>,
              {
                duration: 8000,
                icon: <Package className="h-5 w-5" />,
                action: {
                  label: "View",
                  onClick: () => window.open(`/dashboard/orders/${order._id}`, "_blank")
                }
              }
            );
          });
          
          // Play notification sound
          playNotificationSound();
          
          // Update the state with new orders for the dropdown
          setNewOrders(prev => [...latestNewOrders, ...prev].slice(0, 10));
          
          // Invalidate order cache to ensure all components refresh
          cacheUtils.invalidateOrderData();
        }
      } catch (error) {
        console.error("Error checking for new orders:", error);
      }
    };

    // Check for new orders every minute
    const orderInterval = setInterval(checkForNewOrders, 60000);
    
    // Initial check for orders
    checkForNewOrders();
    
    return () => {
      clearInterval(orderInterval);
    };
  }, []);

  // Fetch unread chat counts
  useEffect(() => {
    // Only run this on dashboard pages, but not on admin pages
    if (typeof window === 'undefined' || !window.location.pathname.includes("/dashboard") || window.location.pathname.includes("/dashboard/admin")) return;
    
    const fetchUnreadCounts = async () => {
      try {
        // Get vendor ID from token
        const vendorId = getVendorIdFromToken();
        
        // Use clientFetch which will properly route through Next.js API rewrites
        const response = await clientFetch(`/chats/vendor/${vendorId}/unread`);
        
        // Check if there are new notifications and play sound if needed
        if (!loading && response.totalUnread > previousUnreadTotal) {
          playNotificationSound();
        }
        
        // Update chat state - note that clientFetch already parses the JSON response
        setUnreadCounts(response);
        setPreviousUnreadTotal(response.totalUnread);
        
        if (response.totalUnread > 0) {
          const chatIds = Object.keys(response.chatCounts);
          
          if (chatIds.length > 0) {
            // Create a simplified metadata object with just needed info
            const metadata: Record<string, { buyerId: string }> = {};
            
            // Fetch each chat to get buyer IDs
            await Promise.all(
              chatIds.map(async (chatId) => {
                try {
                  // Use markAsRead=false to ensure we don't mark messages as read
                  const chatResponse = await clientFetch(`/chats/${chatId}?markAsRead=false`);
                  metadata[chatId] = {
                    buyerId: chatResponse.buyerId,
                  };
                } catch (error) {
                  console.error(`Error fetching chat ${chatId}:`, error);
                }
              })
            );
            
            setChatMetadata(metadata);
          }
        }
        
        setLoading(false);
      } catch (error) {
        console.error("Error fetching unread counts:", error);
        setLoading(false);
      }
    };
    
    // Initial fetch
    fetchUnreadCounts();
    
    // Set polling interval (every 10 seconds for more responsive chat notifications)
    const chatInterval = setInterval(fetchUnreadCounts, 10000);
    
    return () => clearInterval(chatInterval);
  }, [loading, previousUnreadTotal]);

  // Clear notification handlers
  const clearOrderNotifications = () => {
    setNewOrders([]);
    localStorage.removeItem(STORAGE_KEYS.NEW_ORDERS);
  };

  const contextValue: NotificationContextType = {
    unreadCounts,
    chatMetadata,
    newOrders,
    clearOrderNotifications,
    totalNotifications,
    loading,
  };

  return (
    <NotificationContext.Provider value={contextValue}>
      {children}
    </NotificationContext.Provider>
  );
}

export function useNotifications() {
  const context = useContext(NotificationContext);
  if (context === undefined) {
    throw new Error('useNotifications must be used within a NotificationProvider');
  }
  return context;
} 