import { useCallback, useEffect, useRef } from "react";

import { useAppStore } from "@/store/use-app-store";
import type { Point } from "@/types/api";

function geolocationErrorMessage(error: GeolocationPositionError): string {
  switch (error.code) {
    case error.PERMISSION_DENIED:
      return "location.error.permissionDenied";
    case error.POSITION_UNAVAILABLE:
      return "location.error.unavailable";
    case error.TIMEOUT:
      return "location.error.timeout";
    default:
      return "location.error.generic";
  }
}

export function useUserLocation() {
  const setUserLocation = useAppStore(state => state.setUserLocation);
  const setLocationError = useAppStore(state => state.setLocationError);
  const setIsRequestingLocation = useAppStore(state => state.setIsRequestingLocation);
  const watchIdRef = useRef<number | null>(null);

  const clearWatch = useCallback(() => {
    if (typeof navigator === "undefined" || !navigator.geolocation) {
      return;
    }
    if (watchIdRef.current !== null) {
      navigator.geolocation.clearWatch(watchIdRef.current);
      watchIdRef.current = null;
    }
  }, []);

  const start = useCallback(() => {
    if (typeof navigator === "undefined" || !navigator.geolocation) {
      setLocationError("location.error.unsupported");
      setIsRequestingLocation(false);
      return;
    }

    clearWatch();
    setIsRequestingLocation(true);
    setLocationError(null);

    navigator.geolocation.getCurrentPosition(
      position => {
        const coords: Point = { lat: position.coords.latitude, lng: position.coords.longitude };
        setUserLocation(coords);
        setIsRequestingLocation(false);
        setLocationError(null);
      },
      geoError => {
        setUserLocation(null);
        setLocationError(geolocationErrorMessage(geoError));
        setIsRequestingLocation(false);
      },
      { enableHighAccuracy: true, timeout: 10000 }
    );

    const watchId = navigator.geolocation.watchPosition(
      position => {
        const coords: Point = { lat: position.coords.latitude, lng: position.coords.longitude };
        setUserLocation(coords);
        setLocationError(null);
        setIsRequestingLocation(false);
      },
      geoError => {
        setUserLocation(null);
        setLocationError(geolocationErrorMessage(geoError));
        setIsRequestingLocation(false);
      },
      { enableHighAccuracy: true, maximumAge: 15000, timeout: 10000 }
    );

    watchIdRef.current = watchId;
  }, [clearWatch, setIsRequestingLocation, setLocationError, setUserLocation]);

  useEffect(() => {
    start();

    return () => {
      clearWatch();
    };
  }, [clearWatch, start]);

  return {
    refresh: start,
  };
}
