import { useAuth } from "@/_core/hooks/useAuth";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Badge } from "@/components/ui/badge";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Slider } from "@/components/ui/slider";
import { buildMaterialReturnFinalPdfViewerHref } from "@/lib/materialReturnFinalPdf";
import { trpc } from "@/lib/trpc";
import { associationCommuneOptions, getAssociationCommuneLabel, type AssociationCommuneFilter } from "@shared/associationCommunes";
import { associationThematicOptions, getAssociationThematicLabel, getAssociationThematicLabels, type AssociationThematic } from "@shared/associationThematics";
import { ArrowLeft, Building2, Loader2, MapPinned, PackageCheck, Search } from "lucide-react";
import { useEffect, useMemo, useState } from "react";
import { Link } from "wouter";
import { AssociationPublicMap } from "@/components/AssociationPublicMap";
import { toast } from "sonner";

type LogisticsMapEvent = {
  requestId: number;
  title: string;
  associationName: string;
  commune: string;
  manifestationStart: string;
  manifestationEnd: string;
  pickupDate: string;
  restitutionDate: string;
  useStartDate: string;
  useEndDate: string;
  requestedItems: Array<{
    key: string;
    label: string;
    quantity: number;
    granted: boolean;
    requested: boolean;
    extra: string;
  }>;
  boardState: string;
  boardStateLabel: string;
  logisticServiceLabel: string;
  issueFlag: boolean;
  finalPdfUrl: string | null;
  uploadLink: string | null;
};

function haversineDistanceKm(a: { latitude: number; longitude: number }, b: { latitude: number; longitude: number }) {
  const toRad = (value: number) => (value * Math.PI) / 180;
  const earthRadiusKm = 6371;
  const deltaLat = toRad(b.latitude - a.latitude);
  const deltaLng = toRad(b.longitude - a.longitude);
  const lat1 = toRad(a.latitude);
  const lat2 = toRad(b.latitude);

  const hav =
    Math.sin(deltaLat / 2) ** 2 +
    Math.cos(lat1) * Math.cos(lat2) * Math.sin(deltaLng / 2) ** 2;

  return 2 * earthRadiusKm * Math.asin(Math.sqrt(hav));
}

export default function AssociationMapPublic() {
  const { isAuthenticated, user } = useAuth();
  const isAdmin = user?.role === "admin" || user?.role === "super_admin";
  const [search, setSearch] = useState("");
  const [communeFilter, setCommuneFilter] = useState<AssociationCommuneFilter>("all");
  const [thematiqueFilter, setThematiqueFilter] = useState<AssociationThematic | "all">("all");
  const [mapMode, setMapMode] = useState<"annuaire" | "densite" | "logistique">("annuaire");
  const [selectedAssociationId, setSelectedAssociationId] = useState<number | null>(null);
  const [selectedLogisticsRequestId, setSelectedLogisticsRequestId] = useState<number | null>(null);
  const [radiusEnabled, setRadiusEnabled] = useState(false);
  const [radiusKm, setRadiusKm] = useState(5);
  const [userPosition, setUserPosition] = useState<{ latitude: number; longitude: number } | null>(null);
  const [geolocating, setGeolocating] = useState(false);
  const [logisticsFilter, setLogisticsFilter] = useState<"actifs" | "avenir" | "tous">("actifs");

  const { data, isLoading } = trpc.associationDirectory.listMap.useQuery({
    search: search || undefined,
    commune: communeFilter,
    thematique: thematiqueFilter,
    registrationStatus: "all",
    limit: 500,
  });

  const materialCalendarQuery = trpc.request.getMaterialCalendar.useQuery(undefined, {
    enabled: isAdmin,
  });
  const { data: associationMapSettings } = trpc.settings.getAssociationMap.useQuery();

  useEffect(() => {
    if (mapMode === "logistique" && !isAdmin) {
      setMapMode("annuaire");
    }
  }, [isAdmin, mapMode]);

  const requestUserLocation = () => {
    if (!navigator.geolocation) {
      toast.error("La géolocalisation n'est pas disponible sur cet appareil.");
      return;
    }

    setGeolocating(true);
    navigator.geolocation.getCurrentPosition(
      (position) => {
        setUserPosition({
          latitude: position.coords.latitude,
          longitude: position.coords.longitude,
        });
        setRadiusEnabled(true);
        setGeolocating(false);
      },
      () => {
        toast.error("Impossible de récupérer la position. La carte reste utilisable sans ce filtre.");
        setGeolocating(false);
      },
      {
        enableHighAccuracy: true,
        timeout: 5000,
      }
    );
  };

  const radiusFilteredAssociations = useMemo(() => {
    const entries = data?.data || [];
    if (!radiusEnabled || !userPosition) return entries;

    return entries.filter((entry) => {
      if (entry.latitude === null || entry.longitude === null) return false;
      return haversineDistanceKm(userPosition, {
        latitude: entry.latitude,
        longitude: entry.longitude,
      }) <= radiusKm;
    });
  }, [data?.data, radiusEnabled, radiusKm, userPosition]);

  const logisticsEvents = useMemo<LogisticsMapEvent[]>(() => {
    if (!isAdmin) return [];

    const allEvents: LogisticsMapEvent[] = (materialCalendarQuery.data?.events || []).flatMap((event) => {
      if (typeof event.requestId !== "number") {
        return [];
      }

      return [{
          requestId: event.requestId,
          title: event.title,
          associationName: event.associationName,
          commune: event.commune,
          manifestationStart: event.manifestationStart,
          manifestationEnd: event.manifestationEnd,
          pickupDate: event.pickupDate,
          restitutionDate: event.restitutionDate,
          useStartDate: event.useStartDate,
          useEndDate: event.useEndDate,
          requestedItems: event.requestedItems,
          boardState: event.boardState,
          boardStateLabel: event.boardStateLabel,
          logisticServiceLabel: event.logisticServiceLabel,
          issueFlag: event.issueFlag,
          finalPdfUrl: event.finalPdfUrl,
          uploadLink: event.uploadLink,
        }];
      });
    const today = new Date().toISOString().slice(0, 10);

    return allEvents.filter((event) => {
      if (communeFilter !== "all" && event.commune?.toLowerCase() !== communeFilter.toLowerCase()) {
        return false;
      }

      if (search) {
        const haystack = `${event.associationName} ${event.title} ${event.commune} ${event.requestedItems.map((item: any) => item.label).join(" ")}`.toLowerCase();
        if (!haystack.includes(search.toLowerCase())) {
          return false;
        }
      }

      if (logisticsFilter === "tous") return true;
      const start = String(event.useStartDate || "").slice(0, 10);
      const end = String(event.useEndDate || start).slice(0, 10);
      const active = start && end && start <= today && today <= end;
      if (logisticsFilter === "actifs") return active;
      if (logisticsFilter === "avenir") return start > today;
      return true;
    });
  }, [communeFilter, isAdmin, logisticsFilter, materialCalendarQuery.data?.events, search]);

  const selectedAssociation = useMemo(
    () => radiusFilteredAssociations.find((item) => item.id === selectedAssociationId) || null,
    [radiusFilteredAssociations, selectedAssociationId]
  );

  const selectedLogistics = useMemo(
    () => logisticsEvents.find((event) => event.requestId === selectedLogisticsRequestId) || null,
    [logisticsEvents, selectedLogisticsRequestId]
  );

  const densitySummary = useMemo(() => {
    const grouped = new Map<string, number>();
    radiusFilteredAssociations.forEach((entry) => {
      const key = entry.ville || "Commune non renseignée";
      grouped.set(key, (grouped.get(key) || 0) + 1);
    });
    return Array.from(grouped.entries())
      .map(([ville, count]) => ({ ville, count }))
      .sort((a, b) => b.count - a.count);
  }, [radiusFilteredAssociations]);

  const backHref = isAuthenticated ? "/dashboard/associations" : "/associations";
  const visibleCount = mapMode === "logistique" ? logisticsEvents.length : radiusFilteredAssociations.length;

  return (
    <div className="min-h-screen bg-muted/30">
      <header className="border-b border-border bg-white">
        <div className="container py-4">
          <div className="flex items-center justify-between gap-4">
            <div className="flex items-center gap-4">
              <Link href={backHref}>
                <Button variant="ghost" size="icon">
                  <ArrowLeft className="h-5 w-5" />
                </Button>
              </Link>
              <div>
                <h1 className="text-xl font-bold">Carte des associations</h1>
                <p className="text-sm text-muted-foreground">
                  Découvre les associations des Savanes, leur densité territoriale et, côté administration, la circulation du matériel CCDS.
                </p>
              </div>
            </div>
            <div className="flex items-center gap-3">
              <Badge variant="outline" className="bg-primary/5 text-primary border-primary/20">
                {visibleCount} {mapMode === "logistique" ? "mission(s)" : "association(s)"}
              </Badge>
              {isAuthenticated ? (
                <Link href="/dashboard/associations">
                  <Button variant="outline">Annuaire portail</Button>
                </Link>
              ) : null}
            </div>
          </div>
        </div>
      </header>

      <main className="container py-8 space-y-6">
        <Card>
          <CardHeader>
            <CardTitle className="flex items-center gap-2">
              <MapPinned className="h-5 w-5 text-primary" />
              Cartographie interactive & implantation territoriale
            </CardTitle>
            <CardDescription>
              Passe de l'annuaire géographique à la densité d'implantation, puis au pilotage logistique si tu es administrateur.
            </CardDescription>
          </CardHeader>
          <CardContent className="space-y-5">
            <div className="flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between">
              <div className="relative lg:w-[320px]">
                <Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
                <Input
                  placeholder={mapMode === "logistique" ? "Rechercher une mission ou du matériel..." : "Rechercher une association..."}
                  value={search}
                  onChange={(e) => setSearch(e.target.value)}
                  className="pl-9"
                />
              </div>
              <div className="lg:w-[280px]">
                <Select value={thematiqueFilter} onValueChange={(value) => setThematiqueFilter(value as AssociationThematic | "all")}>
                  <SelectTrigger disabled={mapMode === "logistique"}>
                    <SelectValue placeholder="Filtrer par catégorie" />
                  </SelectTrigger>
                  <SelectContent>
                    <SelectItem value="all">Toutes les thématiques</SelectItem>
                    {associationThematicOptions.map((option) => (
                      <SelectItem key={option.value} value={option.value}>
                        {option.label}
                      </SelectItem>
                    ))}
                  </SelectContent>
                </Select>
              </div>
              <div className="flex flex-wrap gap-2">
                {associationCommuneOptions.map((option) => (
                  <Button
                    key={option.value}
                    size="sm"
                    type="button"
                    variant={communeFilter === option.value ? "default" : "outline"}
                    className="rounded-full"
                    onClick={() => setCommuneFilter(option.value)}
                  >
                    {option.label}
                  </Button>
                ))}
              </div>
            </div>

            <div className="flex flex-wrap gap-2">
              <Button
                variant={mapMode === "annuaire" ? "default" : "outline"}
                onClick={() => setMapMode("annuaire")}
              >
                Annuaire géographique
              </Button>
              <Button
                variant={mapMode === "densite" ? "default" : "outline"}
                onClick={() => setMapMode("densite")}
              >
                Densité d'implantation
              </Button>
              {isAdmin ? (
                <Button
                  variant={mapMode === "logistique" ? "default" : "outline"}
                  onClick={() => setMapMode("logistique")}
                >
                  <PackageCheck className="mr-2 h-4 w-4" />
                  Flux logistique événementiel
                </Button>
              ) : null}
            </div>

            <div className="grid gap-4 xl:grid-cols-[1fr_0.8fr]">
              <div className="space-y-3 rounded-lg border bg-muted/20 p-4">
                <div className="flex flex-wrap items-center justify-between gap-3">
                  <div>
                    <p className="text-sm font-medium">Filtre par rayon d'action</p>
                    <p className="text-xs text-muted-foreground">
                      Affiche uniquement les associations autour de ta position pour repérer l'offre locale sur le territoire.
                    </p>
                  </div>
                  <div className="flex gap-2">
                    <Button variant="outline" onClick={requestUserLocation} disabled={geolocating}>
                      {geolocating ? <Loader2 className="mr-2 h-4 w-4 animate-spin" /> : null}
                      {userPosition ? "Actualiser ma position" : "Utiliser ma position"}
                    </Button>
                    {radiusEnabled ? (
                      <Button variant="ghost" onClick={() => setRadiusEnabled(false)}>
                        Désactiver
                      </Button>
                    ) : null}
                  </div>
                </div>
                <div className="space-y-2">
                  <div className="flex items-center justify-between text-sm">
                    <span>Rayon actif</span>
                    <span className="font-medium">{radiusKm} km</span>
                  </div>
                  <Slider
                    value={[radiusKm]}
                    min={1}
                    max={25}
                    step={1}
                    onValueChange={(value) => setRadiusKm(value[0] || 5)}
                    disabled={!userPosition}
                  />
                </div>
              </div>

              {mapMode === "logistique" ? (
                <div className="rounded-lg border bg-muted/20 p-4">
                  <p className="text-sm font-medium">Vue logistique</p>
                  <p className="text-xs text-muted-foreground mb-3">
                    Les missions terrain peuvent être affichées en cours, à venir ou dans une vue complète.
                  </p>
                  <div className="flex flex-wrap gap-2">
                    {([
                      ["actifs", "Actifs aujourd'hui"],
                      ["avenir", "À venir"],
                      ["tous", "Tous les flux"],
                    ] as const).map(([value, label]) => (
                      <Button
                        key={value}
                        variant={logisticsFilter === value ? "default" : "outline"}
                        size="sm"
                        onClick={() => setLogisticsFilter(value)}
                      >
                        {label}
                      </Button>
                    ))}
                  </div>
                </div>
              ) : (
                <div className="rounded-lg border bg-muted/20 p-4">
                  <p className="text-sm font-medium">Lecture territoriale</p>
                  <p className="text-xs text-muted-foreground">
                    {mapMode === "annuaire"
                      ? "La carte regroupe automatiquement les marqueurs quand le nombre d'associations devient dense, puis les détaille au zoom."
                      : "La couche densité montre les zones de concentration associatives pour aider à repérer les secteurs isolés ou saturés."}
                  </p>
                </div>
              )}
            </div>

            <p className="text-sm text-muted-foreground">
              {visibleCount} élément(s) visible(s)
              {communeFilter !== "all" ? ` • ${getAssociationCommuneLabel(communeFilter)}` : ""}
              {thematiqueFilter !== "all" && mapMode !== "logistique" ? ` • ${getAssociationThematicLabel(thematiqueFilter)}` : ""}
              {radiusEnabled && userPosition ? ` • dans un rayon de ${radiusKm} km autour de toi` : ""}
            </p>
          </CardContent>
        </Card>

        <div className="grid gap-6 xl:grid-cols-[minmax(0,1.7fr)_420px]">
          <AssociationPublicMap
            associations={radiusFilteredAssociations}
            mode={mapMode}
            selectedAssociationId={selectedAssociationId}
            onSelectAssociation={(id) => {
              setSelectedAssociationId(id);
              setSelectedLogisticsRequestId(null);
            }}
            logisticsEvents={logisticsEvents}
            selectedLogisticsRequestId={selectedLogisticsRequestId}
            onSelectLogistics={(requestId) => {
              setSelectedLogisticsRequestId(requestId);
              setSelectedAssociationId(null);
            }}
            radiusCenter={radiusEnabled ? userPosition : null}
            radiusKm={radiusEnabled ? radiusKm : 0}
            styleUrl={associationMapSettings?.styleUrl}
          />

          <Card className="min-h-[620px]">
            <CardHeader>
              <CardTitle>
                {mapMode === "annuaire"
                  ? "Associations géolocalisées"
                  : mapMode === "densite"
                    ? "Lecture par commune"
                    : "Missions logistiques"}
              </CardTitle>
              <CardDescription>
                {mapMode === "annuaire"
                  ? "Clique sur une fiche ou un point de la carte pour centrer l'association."
                  : mapMode === "densite"
                    ? "Les zones les plus denses remontent ici pour guider l'analyse territoriale."
                    : "Les prêts de matériel en cours ou à venir deviennent des objets de pilotage cartographique."}
              </CardDescription>
            </CardHeader>
            <CardContent className="space-y-3 max-h-[560px] overflow-auto pr-1">
              {(isLoading || (mapMode === "logistique" && materialCalendarQuery.isLoading)) ? (
                <p className="text-sm text-muted-foreground">Chargement de la carte...</p>
              ) : mapMode === "annuaire" ? (
                radiusFilteredAssociations.length > 0 ? (
                  radiusFilteredAssociations.map((entry) => (
                    <button
                      key={entry.id}
                      type="button"
                      onClick={() => {
                        setSelectedAssociationId(entry.id);
                        setSelectedLogisticsRequestId(null);
                      }}
                      className={`w-full rounded-lg border p-3 text-left transition-colors ${selectedAssociation?.id === entry.id ? "border-primary bg-primary/5" : "hover:bg-muted/40"}`}
                    >
                      <div className="flex items-start justify-between gap-3">
                        <div>
                          <p className="font-medium">{entry.nomAssociation}</p>
                          <p className="text-sm text-muted-foreground">{entry.ville || "Commune non renseignée"}</p>
                          {entry.thematiques?.length ? (
                            <p className="text-sm text-primary">{getAssociationThematicLabels(entry.thematiques).join(" • ")}</p>
                          ) : null}
                        </div>
                        <Badge variant="outline">{entry.registered ? "Inscrite" : "Référencée"}</Badge>
                      </div>
                      {entry.objetAssociation ? (
                        <p className="mt-2 text-sm text-muted-foreground line-clamp-3">{entry.objetAssociation}</p>
                      ) : null}
                      <div className="mt-3">
                        <Link href={entry.publicUrl}>
                          <Button type="button" size="sm" variant="outline">
                            <Building2 className="mr-2 h-4 w-4" />
                            Voir la fiche
                          </Button>
                        </Link>
                      </div>
                    </button>
                  ))
                ) : (
                  <div className="rounded-lg border border-dashed p-4 text-sm text-muted-foreground">
                    Aucune association géolocalisée ne correspond à cette recherche.
                  </div>
                )
              ) : mapMode === "densite" ? (
                densitySummary.length > 0 ? (
                  densitySummary.map((entry) => (
                    <div key={entry.ville} className="rounded-lg border p-3">
                      <div className="flex items-center justify-between gap-3">
                        <p className="font-medium">{entry.ville}</p>
                        <Badge>{entry.count} association(s)</Badge>
                      </div>
                    </div>
                  ))
                ) : (
                  <div className="rounded-lg border border-dashed p-4 text-sm text-muted-foreground">
                    Aucune commune ne remonte dans ce filtre.
                  </div>
                )
              ) : logisticsEvents.length > 0 ? (
                logisticsEvents.map((event) => (
                  <button
                    key={event.requestId}
                    type="button"
                    onClick={() => {
                      setSelectedLogisticsRequestId(event.requestId ?? null);
                      setSelectedAssociationId(null);
                    }}
                    className={`w-full rounded-lg border p-3 text-left transition-colors ${selectedLogistics?.requestId === event.requestId ? "border-primary bg-primary/5" : "hover:bg-muted/40"}`}
                  >
                    <div className="flex items-start justify-between gap-3">
                      <div>
                        <p className="font-medium">{event.associationName}</p>
                        <p className="text-sm text-muted-foreground">{event.commune || "Commune non renseignée"}</p>
                        <p className="text-sm text-primary">{event.boardStateLabel}</p>
                      </div>
                      <Badge variant="outline">{formatDateLabel(event.useStartDate, event.useEndDate)}</Badge>
                    </div>
                    <p className="mt-2 text-sm text-muted-foreground line-clamp-2">
                      {event.requestedItems.map((item) => `${item.label} x${item.quantity}`).join(" • ") || "Matériel non renseigné"}
                    </p>
                    <div className="mt-3 flex flex-wrap gap-2">
                      <Link href={`/dashboard/requests/${event.requestId}`}>
                        <Button type="button" size="sm" variant="outline">
                          Ouvrir le dossier
                        </Button>
                      </Link>
                      {event.finalPdfUrl ? (
                        <a
                          href={buildMaterialReturnFinalPdfViewerHref({
                            url: event.finalPdfUrl,
                            returnTo: "/associations/carte",
                            title: "Consulter le PDF final de restitution",
                            downloadName: `fiche-finale-restitution-${event.requestId}.pdf`,
                          })}
                        >
                          <Button type="button" size="sm" variant="outline">
                            PDF final
                          </Button>
                        </a>
                      ) : null}
                    </div>
                  </button>
                ))
              ) : (
                <div className="rounded-lg border border-dashed p-4 text-sm text-muted-foreground">
                  Aucune mission logistique ne correspond à cette lecture.
                </div>
              )}
            </CardContent>
          </Card>
        </div>
      </main>
    </div>
  );
}

function formatDateLabel(start?: string | null, end?: string | null) {
  if (!start) return "-";
  const startLabel = new Date(start).toLocaleDateString("fr-FR", {
    day: "2-digit",
    month: "2-digit",
  });
  const endLabel = new Date(end || start).toLocaleDateString("fr-FR", {
    day: "2-digit",
    month: "2-digit",
  });
  if (startLabel === endLabel) return startLabel;
  return `${startLabel} -> ${endLabel}`;
}
