"use client";

import * as React from "react";
import {
  CLIENT_GEO_KEYS,
  clearPersistedClientGeo,
  persistClientGeo,
  queryGeolocationPermission,
} from "@/lib/client-geo";
import { refreshClientPublicIp } from "@/lib/client-public-ip";

const THROTTLE_MS = 45_000;

const geoOptions: PositionOptions = {
  enableHighAccuracy: false,
  maximumAge: 300_000,
  timeout: 45_000,
};

function useGeoWatch(
  enabled: boolean,
  onPermissionDenied: () => void,
): void {
  React.useEffect(() => {
    if (!enabled || typeof window === "undefined" || !("geolocation" in navigator)) {
      return;
    }

    let lastWrite = 0;

    const onSuccess = (pos: GeolocationPosition) => {
      const now = Date.now();
      if (now - lastWrite < THROTTLE_MS) return;
      lastWrite = now;
      persistClientGeo(pos);
    };

    const onError = (err: GeolocationPositionError) => {
      if (err.code === 1) {
        clearPersistedClientGeo();
        onPermissionDenied();
      }
    };

    navigator.geolocation.getCurrentPosition(
      (pos) => {
        lastWrite = Date.now();
        persistClientGeo(pos);
      },
      onError,
      geoOptions,
    );

    const watchId = navigator.geolocation.watchPosition(
      onSuccess,
      onError,
      geoOptions,
    );

    return () => {
      navigator.geolocation.clearWatch(watchId);
    };
  }, [enabled, onPermissionDenied]);
}

/**
 * Resolves public IP for activity-log headers; requests coordinates only via
 * `navigator.geolocation` (native browser permission UI, no third-party geo APIs).
 */
export function ClientGeoProvider() {
  const [watchEnabled, setWatchEnabled] = React.useState(false);

  React.useEffect(() => {
    void refreshClientPublicIp();
  }, []);

  React.useEffect(() => {
    if (typeof window === "undefined" || !("geolocation" in navigator)) {
      return;
    }

    let cancelled = false;

    const tryStartFromStored = (): boolean => {
      const lat = sessionStorage.getItem(CLIENT_GEO_KEYS.lat);
      const lng = sessionStorage.getItem(CLIENT_GEO_KEYS.lng);
      if (lat && lng) {
        setWatchEnabled(true);
        return true;
      }
      return false;
    };

    const requestNativeGeo = () => {
      navigator.geolocation.getCurrentPosition(
        (pos) => {
          if (cancelled) return;
          persistClientGeo(pos);
          setWatchEnabled(true);
        },
        (err) => {
          if (cancelled) return;
          if (err.code === 1) {
            clearPersistedClientGeo();
          }
        },
        geoOptions,
      );
    };

    void (async () => {
      const perm = await queryGeolocationPermission();

      if (cancelled) return;

      if (perm === "granted") {
        setWatchEnabled(true);
        return;
      }

      if (perm === "denied") {
        return;
      }

      if (typeof navigator !== "undefined" && "permissions" in navigator) {
        try {
          const status = await navigator.permissions.query({
            name: "geolocation" as PermissionName,
          });
          status.addEventListener("change", () => {
            if (cancelled) return;
            if (status.state === "granted") {
              setWatchEnabled(true);
            }
          });
        } catch {
          /* ignore */
        }
      }

      if (tryStartFromStored()) return;

      if (perm === "prompt" || perm === "unsupported") {
        requestNativeGeo();
      }
    })();

    return () => {
      cancelled = true;
    };
  }, []);

  const handleDeniedFromWatch = React.useCallback(() => {
    setWatchEnabled(false);
  }, []);

  useGeoWatch(watchEnabled, handleDeniedFromWatch);

  return null;
}
