"use client";

import { useCallback, useEffect, useRef, useState } from "react";
import { ExternalLink, LoaderCircle, LocateFixed, MapPinned, ShieldAlert, X } from "lucide-react";
import { Button } from "@/components/ui/button";
import { useI18n } from "@/lib/i18n";
import { fetchReverseLocation } from "@/lib/location-api";
import { createSelectedLocation, type LocatedSynopStation } from "@/lib/location-utils";
import { useWeatherStore } from "@/lib/store";

const GPS_PROMPT_SEEN_KEY = "wtr:gps-prompt-seen";

function roundCoordinate(value: number) {
  return Number(value.toFixed(3));
}

export function CurrentLocationControl({ stations }: { stations: LocatedSynopStation[] }) {
  const { language, t } = useI18n();
  const selectLocation = useWeatherStore((state) => state.selectLocation);
  const [showPrompt, setShowPrompt] = useState(false);
  const [isLocating, setIsLocating] = useState(false);
  const [message, setMessage] = useState<string | null>(null);
  const [isSecureContext, setIsSecureContext] = useState(true);
  const autoLocated = useRef(false);

  const dismissPrompt = useCallback(() => {
    window.localStorage.setItem(GPS_PROMPT_SEEN_KEY, "true");
    setShowPrompt(false);
  }, []);

  const locate = useCallback(() => {
    dismissPrompt();
    setMessage(null);
    if (!window.isSecureContext) {
      setMessage(t("location.gpsSecureContext"));
      return;
    }
    if (!navigator.geolocation) {
      setMessage(t("location.gpsUnavailable"));
      return;
    }
    setIsLocating(true);
    navigator.geolocation.getCurrentPosition(
      async ({ coords }) => {
        const latitude = roundCoordinate(coords.latitude);
        const longitude = roundCoordinate(coords.longitude);
        try {
          const place = await fetchReverseLocation(latitude, longitude, language).catch(() => ({
            name: t("location.gpsFallbackName"),
            province: null,
            district: null,
            country: null,
            countryCode: null,
            admin1: null,
            admin2: null,
            timezone: null,
            region: "GLOBAL" as const,
          }));
          const selected = createSelectedLocation({ ...place, latitude, longitude }, stations);
          selectLocation(selected);
          setMessage(t("location.gpsSelected", { location: selected.name }));
        } catch {
          setMessage(t("location.gpsPositionUnavailable"));
        } finally {
          setIsLocating(false);
        }
      },
      (error) => {
        setIsLocating(false);
        setMessage(error.code === error.PERMISSION_DENIED
          ? t("location.gpsDenied")
          : error.code === error.TIMEOUT
            ? t("location.gpsTimeout")
            : t("location.gpsPositionUnavailable"));
      },
      { enableHighAccuracy: true, maximumAge: 5 * 60 * 1000, timeout: 12_000 },
    );
  }, [dismissPrompt, language, selectLocation, stations, t]);

  useEffect(() => {
    const animationFrame = window.requestAnimationFrame(() => {
      setIsSecureContext(window.isSecureContext);
      if (window.localStorage.getItem(GPS_PROMPT_SEEN_KEY) !== "true") setShowPrompt(true);
    });
    return () => window.cancelAnimationFrame(animationFrame);
  }, []);

  useEffect(() => {
    if (!window.isSecureContext || autoLocated.current || !navigator.permissions?.query) return;
    navigator.permissions.query({ name: "geolocation" }).then((permission) => {
      if (permission.state !== "granted" || autoLocated.current) return;
      autoLocated.current = true;
      locate();
    }).catch(() => undefined);
  }, [locate]);

  return (
    <div className="mt-3 space-y-2">
      {showPrompt && (
        <div className="glass-subtle rounded-card p-3.5">
          <div className="flex items-start gap-3">
            <div className="rounded-control bg-accent/10 p-2 text-accent"><MapPinned className="size-4" /></div>
            <div className="min-w-0 flex-1">
              <p className="text-sm font-semibold">{t("location.gpsPromptTitle")}</p>
              <p className="mt-1 text-xs leading-5 text-muted">{t("location.gpsPromptDescription")}</p>
              {!isSecureContext && <p className="mt-2 flex items-start gap-1.5 text-xs leading-5 text-warning"><ShieldAlert className="mt-0.5 size-3.5 shrink-0" />{t("location.gpsSecureContext")}</p>}
              <div className="mt-3 flex flex-wrap gap-2">
                <Button type="button" onClick={locate} disabled={isLocating}>
                  {isLocating ? <LoaderCircle className="size-4 animate-spin" /> : <LocateFixed className="size-4" />}
                  {isLocating ? t("location.gpsLocating") : t("location.gpsAllow")}
                </Button>
                <Button type="button" variant="ghost" onClick={dismissPrompt}><X className="size-4" />{t("location.gpsNotNow")}</Button>
              </div>
            </div>
          </div>
        </div>
      )}
      {!showPrompt && (
        <div className="flex flex-wrap items-center gap-x-3 gap-y-2">
          <Button type="button" variant="glass" onClick={locate} disabled={isLocating}>
            {isLocating ? <LoaderCircle className="size-4 animate-spin" /> : <LocateFixed className="size-4" />}
            {isLocating ? t("location.gpsLocating") : t("location.gpsUse")}
          </Button>
          {message && <p aria-live="polite" className="max-w-xl text-xs leading-5 text-muted">{message}</p>}
        </div>
      )}
      <p className="text-[0.68rem] text-muted">
        {t("location.gpsAttribution")} <a href="https://www.openstreetmap.org/copyright" target="_blank" rel="noreferrer" className="inline-flex items-center gap-1 underline decoration-muted/60 underline-offset-2 transition hover:text-accent">OpenStreetMap <ExternalLink className="size-3" /></a>
      </p>
    </div>
  );
}
