/**
 * Resource Location Hook
 *
 * Fetches the latest location for a resource's linked staff member.
 * Used for tracking staff during en route jobs.
 */

import { useQuery, useQueryClient } from '@tanstack/react-query';
import { useEffect, useRef, useCallback } from 'react';
import apiClient from '../api/client';

export interface ResourceLocation {
  hasLocation: boolean;
  latitude?: number;
  longitude?: number;
  accuracy?: number;
  heading?: number;
  speed?: number;
  timestamp?: string;
  isTracking: boolean;
  activeJob?: {
    id: number;
    title: string;
    status: string;
    statusDisplay: string;
  } | null;
  message?: string;
}

interface BackendLocationResponse {
  has_location: boolean;
  latitude?: number;
  longitude?: number;
  accuracy?: number;
  heading?: number;
  speed?: number;
  timestamp?: string;
  is_tracking?: boolean;
  active_job?: {
    id: number;
    title: string;
    status: string;
    status_display: string;
  } | null;
  message?: string;
}

/**
 * Hook to fetch a resource's latest location
 */
export const useResourceLocation = (resourceId: string | null, options?: { enabled?: boolean }) => {
  return useQuery<ResourceLocation>({
    queryKey: ['resourceLocation', resourceId],
    queryFn: async () => {
      const { data } = await apiClient.get<BackendLocationResponse>(`/resources/${resourceId}/location/`);

      return {
        hasLocation: data.has_location,
        latitude: data.latitude,
        longitude: data.longitude,
        accuracy: data.accuracy,
        heading: data.heading,
        speed: data.speed,
        timestamp: data.timestamp,
        isTracking: data.is_tracking ?? false,
        activeJob: data.active_job ? {
          id: data.active_job.id,
          title: data.active_job.title,
          status: data.active_job.status,
          statusDisplay: data.active_job.status_display,
        } : null,
        message: data.message,
      };
    },
    enabled: !!resourceId && (options?.enabled !== false),
    refetchInterval: false, // We'll use WebSocket for live updates instead
    staleTime: 30000, // Consider data stale after 30 seconds
  });
};

/**
 * Hook for live location updates via WebSocket
 *
 * Connects to WebSocket when enabled and updates the query cache
 * when new location data arrives.
 */
export const useLiveResourceLocation = (
  resourceId: string | null,
  options?: { enabled?: boolean }
) => {
  const queryClient = useQueryClient();
  const wsRef = useRef<WebSocket | null>(null);
  const reconnectTimeoutRef = useRef<NodeJS.Timeout | null>(null);

  const connect = useCallback(() => {
    if (!resourceId || options?.enabled === false) return;

    // Get WebSocket URL from current host
    const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
    const host = window.location.hostname;
    const port = '8000'; // Backend port
    const wsUrl = `${protocol}//${host}:${port}/ws/resource-location/${resourceId}/`;

    try {
      const ws = new WebSocket(wsUrl);
      wsRef.current = ws;

      ws.onopen = () => {
        console.log('[useLiveResourceLocation] WebSocket connected for resource:', resourceId);
      };

      ws.onmessage = (event) => {
        try {
          const data = JSON.parse(event.data);

          if (data.type === 'location_update') {
            // Update the query cache with new location data
            queryClient.setQueryData<ResourceLocation>(['resourceLocation', resourceId], (old) => ({
              ...old,
              hasLocation: true,
              latitude: data.latitude,
              longitude: data.longitude,
              accuracy: data.accuracy,
              heading: data.heading,
              speed: data.speed,
              timestamp: data.timestamp,
              isTracking: true,
              activeJob: data.active_job ? {
                id: data.active_job.id,
                title: data.active_job.title,
                status: data.active_job.status,
                statusDisplay: data.active_job.status_display,
              } : old?.activeJob ?? null,
            }));
          } else if (data.type === 'tracking_stopped') {
            // Staff stopped tracking
            queryClient.setQueryData<ResourceLocation>(['resourceLocation', resourceId], (old) => ({
              ...old,
              hasLocation: old?.hasLocation ?? false,
              isTracking: false,
            }));
          }
        } catch (err) {
          console.error('[useLiveResourceLocation] Failed to parse message:', err);
        }
      };

      ws.onerror = (error) => {
        console.error('[useLiveResourceLocation] WebSocket error:', error);
      };

      ws.onclose = (event) => {
        console.log('[useLiveResourceLocation] WebSocket closed:', event.code, event.reason);
        wsRef.current = null;

        // Reconnect after 5 seconds if not a clean close
        if (event.code !== 1000 && options?.enabled !== false) {
          reconnectTimeoutRef.current = setTimeout(() => {
            connect();
          }, 5000);
        }
      };
    } catch (err) {
      console.error('[useLiveResourceLocation] Failed to connect:', err);
    }
  }, [resourceId, options?.enabled, queryClient]);

  useEffect(() => {
    connect();

    return () => {
      if (reconnectTimeoutRef.current) {
        clearTimeout(reconnectTimeoutRef.current);
      }
      if (wsRef.current) {
        wsRef.current.close(1000, 'Component unmounting');
        wsRef.current = null;
      }
    };
  }, [connect]);

  // Return a function to manually refresh
  return {
    refresh: () => queryClient.invalidateQueries({ queryKey: ['resourceLocation', resourceId] }),
  };
};
