import React, { createContext, useContext, useState, useCallback, useEffect, useRef, useMemo } from 'react';
import roomService, { Room } from '../services/roomService';
import advancedRoomService, { RoomStatusBoardItem } from '../services/advancedRoomService';
import { toast } from 'react-toastify';
import { logger } from '../../../shared/utils/logger';

interface RoomContextType {
  // Room list state
  rooms: Room[];
  roomsLoading: boolean;
  roomsError: string | null;
  
  // Room status board state
  statusBoardRooms: RoomStatusBoardItem[];
  statusBoardLoading: boolean;
  statusBoardError: string | null;
  
  // Actions
  refreshRooms: () => Promise<void>;
  refreshStatusBoard: (floor?: number) => Promise<void>;
  updateRoom: (roomId: number, updates: Partial<Room>) => Promise<void>;
  deleteRoom: (roomId: number) => Promise<void>;
  createRoom: (roomData: Partial<Room> & { room_number: string; floor: number; room_type_id: number; status: 'available' | 'occupied' | 'maintenance' }) => Promise<void>;
  
  // Filters and pagination
  setRoomFilters: (filters: { search?: string; status?: string; type?: string }) => void;
  roomFilters: { search: string; status: string; type: string };
  setRoomPage: (page: number) => void;
  roomPage: number;
  
  // Status board filters
  setStatusBoardFloor: (floor: number | null) => void;
  statusBoardFloor: number | null;
  
  // Last update timestamp for synchronization
  lastUpdate: number;
}

const RoomContext = createContext<RoomContextType | undefined>(undefined);

// eslint-disable-next-line react-refresh/only-export-components
export const useRoomContext = () => {
  const context = useContext(RoomContext);
  if (!context) {
    // Provide a more helpful error message with debugging info
    const error = new Error(
      'useRoomContext must be used within a RoomProvider. ' +
      'Make sure RoomProvider wraps your component tree in App.tsx'
    );
    if (import.meta.env.DEV) {
      console.error('RoomContext Error:', {
        context,
        stack: error.stack,
        // Check if we're in a development environment
        isDev: import.meta.env.DEV,
        hint: 'This error usually occurs when: 1) Component is rendered outside RoomProvider, 2) Hot module reload issue, 3) Context provider not mounted yet',
      });
    }
    throw error;
  }
  return context;
};

interface RoomProviderProps {
  children: React.ReactNode;
}

export const RoomProvider: React.FC<RoomProviderProps> = ({ children }) => {
  // Room list state
  const [rooms, setRooms] = useState<Room[]>([]);
  const [roomsLoading, setRoomsLoading] = useState(false);
  const [roomsError, setRoomsError] = useState<string | null>(null);
  
  // Room status board state
  const [statusBoardRooms, setStatusBoardRooms] = useState<RoomStatusBoardItem[]>([]);
  const [statusBoardLoading, setStatusBoardLoading] = useState(false);
  const [statusBoardError, setStatusBoardError] = useState<string | null>(null);
  
  // Filters and pagination
  const [roomFilters, setRoomFiltersState] = useState({ search: '', status: '', type: '' });
  const [roomPage, setRoomPageState] = useState(1);
  const [statusBoardFloor, setStatusBoardFloorState] = useState<number | null>(null);
  
  // Last update timestamp
  const [lastUpdate, setLastUpdate] = useState<number>(Date.now());
  
  // Abort controllers for cleanup
  const roomsAbortRef = useRef<AbortController | null>(null);
  const statusBoardAbortRef = useRef<AbortController | null>(null);
  
  // Auto-refresh interval (30 seconds)
  const autoRefreshIntervalRef = useRef<NodeJS.Timeout | null>(null);
  
  // Refresh rooms list - fetch all rooms for better sync across components
  const refreshRooms = useCallback(async () => {
    // Cancel previous request
    if (roomsAbortRef.current) {
      roomsAbortRef.current.abort();
    }
    
    // Create new abort controller
    roomsAbortRef.current = new AbortController();
    
    try {
      setRoomsLoading(true);
      setRoomsError(null);
      
      // Fetch rooms with reasonable pagination
      // Individual components can handle their own pagination/filtering
      const response = await roomService.getRooms({
        limit: 100, // Reasonable batch size for sync
        page: 1,
      }, roomsAbortRef.current.signal);
      
      if (response.data?.rooms) {
        setRooms(response.data.rooms);
        setLastUpdate(Date.now());
      }
    } catch (error: unknown) {
      // Type guard for abort errors
      const isAbortError = (e: unknown): boolean => {
        if (typeof e === 'object' && e !== null) {
          const err = e as { name?: string; code?: string; isCancelled?: boolean };
          return err.name === 'AbortError' || err.code === 'ERR_CANCELED' || err.isCancelled === true;
        }
        return false;
      };
      
      if (isAbortError(error)) {
        return;
      }
      logger.error('Error refreshing rooms', error);
      setRoomsError(getUserFriendlyError(error) || 'Failed to refresh rooms');
      // Don't show toast on every auto-refresh, only on manual refresh
    } finally {
      setRoomsLoading(false);
    }
  }, []);
  
  // Refresh status board
  const refreshStatusBoard = useCallback(async (floor?: number) => {
    // Cancel previous request
    if (statusBoardAbortRef.current) {
      statusBoardAbortRef.current.abort();
    }
    
    // Create new abort controller
    statusBoardAbortRef.current = new AbortController();
    
    try {
      setStatusBoardLoading(true);
      setStatusBoardError(null);
      
      const response = await advancedRoomService.getRoomStatusBoard(
        floor || statusBoardFloor || undefined,
        statusBoardAbortRef.current.signal
      );
      
      if (response.status === 'success' && response.data?.rooms) {
        setStatusBoardRooms(response.data.rooms);
        setLastUpdate(Date.now());
      }
    } catch (error: unknown) {
      // Type guard for abort errors
      const isAbortError = (e: unknown): boolean => {
        if (typeof e === 'object' && e !== null) {
          const err = e as { name?: string; code?: string; isCancelled?: boolean };
          return err.name === 'AbortError' || err.code === 'ERR_CANCELED' || err.isCancelled === true;
        }
        return false;
      };
      
      if (isAbortError(error)) {
        return;
      }
      
      // Handle 401 Unauthorized gracefully - user may not have admin/staff role
      if (getUserFriendlyError(error) === 401) {
        setStatusBoardError(null); // Don't set error for unauthorized access
        setStatusBoardRooms([]); // Clear status board if unauthorized
        return; // Silently return without logging
      }
      
      logger.error('Error refreshing status board', error);
      setStatusBoardError(getUserFriendlyError(error) || 'Failed to refresh status board');
      // Don't show toast on every auto-refresh, only on manual refresh
    } finally {
      setStatusBoardLoading(false);
    }
  }, [statusBoardFloor]);
  
  // Update room
  const updateRoom = useCallback(async (roomId: number, updates: Partial<Room>) => {
    try {
      await roomService.updateRoom(roomId, updates);
      toast.success('Room updated successfully');
      
      // Refresh both views to ensure they're in sync
      await Promise.all([
        refreshRooms(),
        refreshStatusBoard(),
      ]);
    } catch (error: unknown) {
      logger.error('Error updating room', error);
      toast.error(getUserFriendlyError(error) || 'Failed to update room');
      throw error;
    }
  }, [refreshRooms, refreshStatusBoard]);
  
  // Delete room
  const deleteRoom = useCallback(async (roomId: number) => {
    try {
      await roomService.deleteRoom(roomId);
      toast.success('Room deleted successfully');
      
      // Refresh both views
      await Promise.all([
        refreshRooms(),
        refreshStatusBoard(),
      ]);
    } catch (error: unknown) {
      logger.error('Error deleting room', error);
      toast.error(getUserFriendlyError(error) || 'Failed to delete room');
      throw error;
    }
  }, [refreshRooms, refreshStatusBoard]);
  
  // Create room
  const createRoom = useCallback(async (roomData: Partial<Room> & { room_number: string; floor: number; room_type_id: number; status: 'available' | 'occupied' | 'maintenance' }) => {
    try {
      await roomService.createRoom(roomData as Partial<Room> & { room_number: string; floor: number; room_type_id: number; status: 'available' | 'occupied' | 'maintenance' });
      toast.success('Room created successfully');
      
      // Refresh both views
      await Promise.all([
        refreshRooms(),
        refreshStatusBoard(),
      ]);
    } catch (error: unknown) {
      logger.error('Error creating room', error);
      toast.error(getUserFriendlyError(error) || 'Failed to create room');
      throw error;
    }
  }, [refreshRooms, refreshStatusBoard]);
  
  // Set room filters
  const setRoomFilters = useCallback((filters: { search?: string; status?: string; type?: string }) => {
    setRoomFiltersState(prev => ({ ...prev, ...filters }));
    setRoomPageState(1); // Reset to first page when filters change
  }, []);
  
  // Set room page
  const setRoomPage = useCallback((page: number) => {
    setRoomPageState(page);
  }, []);
  
  // Set status board floor
  const setStatusBoardFloor = useCallback((floor: number | null) => {
    setStatusBoardFloorState(floor);
  }, []);
  
  // Initial load - only fetch rooms, status board will be fetched when needed
  useEffect(() => {
    refreshRooms();
    // Don't fetch status board on initial load - it requires admin/staff role
    // It will be fetched when the component that needs it mounts
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []); // refreshRooms is stable (useCallback with empty deps), so this is safe
  
  // Initial load and periodic refresh handled by auto-refresh interval
  
  // Auto-refresh status board when floor changes (only if component using it is mounted)
  // This will be called by AdvancedRoomManagementPage when floor filter changes
  
  // Set up auto-refresh interval (every 60 seconds)
  // Pause when tab is inactive to save resources
  useEffect(() => {
    let intervalId: NodeJS.Timeout | null = null;
    
    const startRefresh = () => {
      if (intervalId) clearInterval(intervalId);
      intervalId = setInterval(() => {
        if (!document.hidden) {
          refreshRooms();
        }
      }, 60000); // 60 seconds
    };
    
    const handleVisibilityChange = () => {
      if (document.hidden) {
        // Pause refresh when tab is hidden
        if (intervalId) {
          clearInterval(intervalId);
          intervalId = null;
        }
      } else {
        // Resume refresh when tab becomes visible
        startRefresh();
        // Immediate refresh when tab becomes visible
        refreshRooms();
      }
    };
    
    startRefresh();
    document.addEventListener('visibilitychange', handleVisibilityChange);
    
    return () => {
      if (intervalId) {
        clearInterval(intervalId);
      }
      document.removeEventListener('visibilitychange', handleVisibilityChange);
    };
  }, [refreshRooms]);
  
  // Cleanup on unmount
  useEffect(() => {
    const autoRefreshInterval = autoRefreshIntervalRef.current;
    return () => {
      if (roomsAbortRef.current) {
        roomsAbortRef.current.abort();
      }
      if (statusBoardAbortRef.current) {
        statusBoardAbortRef.current.abort();
      }
      if (autoRefreshInterval) {
        clearInterval(autoRefreshInterval);
      }
    };
  }, []);
  
  const value: RoomContextType = useMemo(() => ({
    rooms,
    roomsLoading,
    roomsError,
    statusBoardRooms,
    statusBoardLoading,
    statusBoardError,
    refreshRooms,
    refreshStatusBoard,
    updateRoom,
    deleteRoom,
    createRoom,
    setRoomFilters,
    roomFilters,
    setRoomPage,
    roomPage,
    setStatusBoardFloor,
    statusBoardFloor,
    lastUpdate,
  }), [
    rooms,
    roomsLoading,
    roomsError,
    statusBoardRooms,
    statusBoardLoading,
    statusBoardError,
    refreshRooms,
    refreshStatusBoard,
    updateRoom,
    deleteRoom,
    createRoom,
    setRoomFilters,
    roomFilters,
    setRoomPage,
    roomPage,
    setStatusBoardFloor,
    statusBoardFloor,
    lastUpdate,
  ]);
  
  return <RoomContext.Provider value={value}>{children}</RoomContext.Provider>;
};

