"use client";

import {
  createContext,
  useCallback,
  useContext,
  useEffect,
  useMemo,
  useState,
} from "react";

export interface Coordinates {
  lat: number;
  lng: number;
  accuracy: number;
}

export interface LocationAddress {
  city: string;
  district: string;
  displayName: string;
}

type LocationStatus = "idle" | "loading" | "success" | "error";

interface LocationContextValue {
  coords: Coordinates | null;
  address: LocationAddress | null;
  status: LocationStatus;
  error: string | null;
  requestLocation: () => void;
  shortLabel: string | null;
}

const LocationContext = createContext<LocationContextValue | null>(null);

const STORAGE_KEY = "yakinimda-location";

function getGeolocationErrorMessage(code: number): string {
  switch (code) {
    case 1:
      return "Konum izni reddedildi. Tarayıcı ayarlarından izin verebilirsiniz.";
    case 2:
      return "Konum bilgisi alınamadı. Lütfen tekrar deneyin.";
    case 3:
      return "Konum isteği zaman aşımına uğradı.";
    default:
      return "Konum alınırken bir hata oluştu.";
  }
}

async function reverseGeocode(
  lat: number,
  lng: number
): Promise<LocationAddress> {
  const response = await fetch(
    `/api/reverse-geocode?lat=${lat}&lng=${lng}`
  );

  if (!response.ok) {
    throw new Error("Adres bilgisi alınamadı.");
  }

  return response.json();
}

function loadStoredLocation(): {
  coords: Coordinates;
  address: LocationAddress;
} | null {
  if (typeof window === "undefined") return null;

  try {
    const raw = sessionStorage.getItem(STORAGE_KEY);
    if (!raw) return null;
    return JSON.parse(raw);
  } catch {
    return null;
  }
}

function storeLocation(coords: Coordinates, address: LocationAddress) {
  sessionStorage.setItem(STORAGE_KEY, JSON.stringify({ coords, address }));
}

export function LocationProvider({ children }: { children: React.ReactNode }) {
  const [coords, setCoords] = useState<Coordinates | null>(null);
  const [address, setAddress] = useState<LocationAddress | null>(null);
  const [status, setStatus] = useState<LocationStatus>("idle");
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    const stored = loadStoredLocation();
    if (stored) {
      setCoords(stored.coords);
      setAddress(stored.address);
      setStatus("success");
    }
  }, []);

  const requestLocation = useCallback(() => {
    if (typeof window === "undefined") return;

    if (!navigator.geolocation) {
      setStatus("error");
      setError("Tarayıcınız konum özelliğini desteklemiyor.");
      return;
    }

    setStatus("loading");
    setError(null);

    navigator.geolocation.getCurrentPosition(
      async (position) => {
        const nextCoords: Coordinates = {
          lat: position.coords.latitude,
          lng: position.coords.longitude,
          accuracy: position.coords.accuracy,
        };

        setCoords(nextCoords);

        try {
          const nextAddress = await reverseGeocode(
            nextCoords.lat,
            nextCoords.lng
          );
          setAddress(nextAddress);
          storeLocation(nextCoords, nextAddress);
          setStatus("success");
        } catch {
          const fallback: LocationAddress = {
            city: "Konum alındı",
            district: "",
            displayName: `${nextCoords.lat.toFixed(4)}, ${nextCoords.lng.toFixed(4)}`,
          };
          setAddress(fallback);
          storeLocation(nextCoords, fallback);
          setStatus("success");
        }
      },
      (geoError) => {
        setStatus("error");
        setError(getGeolocationErrorMessage(geoError.code));
      },
      {
        enableHighAccuracy: true,
        timeout: 15000,
        maximumAge: 60000,
      }
    );
  }, []);

  const shortLabel = useMemo(() => {
    if (!address) return null;
    if (address.district) return `${address.district}, ${address.city}`;
    return address.city;
  }, [address]);

  const value = useMemo(
    () => ({
      coords,
      address,
      status,
      error,
      requestLocation,
      shortLabel,
    }),
    [coords, address, status, error, requestLocation, shortLabel]
  );

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

export function useLocation() {
  const context = useContext(LocationContext);
  if (!context) {
    throw new Error("useLocation must be used within LocationProvider");
  }
  return context;
}
