/**
 * @ai-summary Hook for browser geolocation API
 */

import { useState, useCallback } from 'react';
import { GeolocationCoordinates, GeolocationError } from '../types/stations.types';

interface UseGeolocationState {
  /** Current coordinates or null if not available */
  coordinates: GeolocationCoordinates | null;
  /** Whether location request is in progress */
  isPending: boolean;
  /** Error if geolocation failed */
  error: GeolocationError | null;
  /** Whether user has granted permission */
  hasPermission: boolean;
}

interface UseGeolocationOptions {
  /** Enable high accuracy (slower but more precise) */
  enableHighAccuracy?: boolean;
  /** Timeout in milliseconds */
  timeout?: number;
  /** Maximum cache age in milliseconds */
  maximumAge?: number;
}

/**
 * Hook for accessing browser geolocation API
 * Handles permissions, errors, and provides methods to request location
 *
 * @example
 * ```tsx
 * const { coordinates, isPending, error, requestLocation } = useGeolocation();
 *
 * return (
 *   <div>
 *     {coordinates && (
 *       <p>Location: {coordinates.latitude}, {coordinates.longitude}</p>
 *     )}
 *     <button onClick={requestLocation} disabled={isPending}>
 *       Get Current Location
 *     </button>
 *     {error && <p>Error: {error}</p>}
 *   </div>
 * );
 * ```
 */
export function useGeolocation(options?: UseGeolocationOptions) {
  const [state, setState] = useState<UseGeolocationState>({
    coordinates: null,
    isPending: false,
    error: null,
    hasPermission: true
  });

  // Request user's current location
  const requestLocation = useCallback(() => {
    if (!navigator?.geolocation) {
      setState((prev) => ({
        ...prev,
        error: GeolocationError.POSITION_UNAVAILABLE
      }));
      return;
    }

    setState((prev) => ({ ...prev, isPending: true, error: null }));

    navigator.geolocation.getCurrentPosition(
      (position) => {
        const { latitude, longitude, accuracy } = position.coords;
        setState({
          coordinates: { latitude, longitude, accuracy },
          isPending: false,
          error: null,
          hasPermission: true
        });
      },
      (error) => {
        let geolocationError = GeolocationError.UNKNOWN;

        switch (error.code) {
          case error.PERMISSION_DENIED:
            geolocationError = GeolocationError.PERMISSION_DENIED;
            break;
          case error.POSITION_UNAVAILABLE:
            geolocationError = GeolocationError.POSITION_UNAVAILABLE;
            break;
          case error.TIMEOUT:
            geolocationError = GeolocationError.TIMEOUT;
            break;
        }

        setState({
          coordinates: null,
          isPending: false,
          error: geolocationError,
          hasPermission:
            geolocationError !== GeolocationError.PERMISSION_DENIED
        });
      },
      {
        enableHighAccuracy: options?.enableHighAccuracy ?? false,
        timeout: options?.timeout ?? 10000,
        maximumAge: options?.maximumAge ?? 0
      }
    );
  }, [options]);

  // Request permission explicitly (iOS 13+)
  const requestPermission = useCallback(async () => {
    if (!navigator?.permissions?.query) {
      // Permissions API not supported, fallback to direct request
      requestLocation();
      return;
    }

    try {
      const permission = await navigator.permissions.query({
        name: 'geolocation'
      });

      if (permission.state === 'granted') {
        setState((prev) => ({ ...prev, hasPermission: true }));
        requestLocation();
      } else if (permission.state === 'prompt') {
        requestLocation();
      } else {
        setState((prev) => ({
          ...prev,
          error: GeolocationError.PERMISSION_DENIED,
          hasPermission: false
        }));
      }
    } catch (error) {
      // Fallback: just request location
      requestLocation();
    }
  }, [requestLocation]);

  // Clear error
  const clearError = useCallback(() => {
    setState((prev) => ({ ...prev, error: null }));
  }, []);

  // Clear coordinates
  const clearLocation = useCallback(() => {
    setState((prev) => ({ ...prev, coordinates: null }));
  }, []);

  return {
    ...state,
    requestLocation,
    requestPermission,
    clearError,
    clearLocation,
    /**
     * Convenience method to get coordinates object
     * Throws error if location not available
     */
    getCoordinates: () => {
      if (!state.coordinates) {
        throw new Error('Location coordinates not available');
      }
      return state.coordinates;
    }
  };
}
