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

import { Layers, Menu, PanelRightClose, PanelRightOpen } from "lucide-react";
import { useTranslation } from "react-i18next";

import { AppHeader } from "@/components/layout/AppHeader";
import { MapViewport } from "@/components/map/MapViewport";
import { ActivityPanel } from "@/components/panels/ActivityPanel";
import { HotspotStatsPanel } from "@/components/panels/HotspotStatsPanel";
import { OverviewPanel } from "@/components/panels/OverviewPanel";
import {
  AlertDialog,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogTitle,
} from "@/components/ui/alert-dialog";
import { Button } from "@/components/ui/button";
import { ScrollArea } from "@/components/ui/scroll-area";
import { Toaster } from "@/components/ui/toaster";
import { useToast } from "@/components/ui/use-toast";
import { useHotspotFeed } from "@/hooks/useHotspotFeed";
import { useLeafletHeatmap, type TileProvider } from "@/hooks/useLeafletHeatmap";
import { useUserLocation } from "@/hooks/useUserLocation";
import { cn, distanceInKm, formatCoordinate, formatRelativeTime, formatTimestamp } from "@/lib/utils";
import { useAppStore } from "@/store/useAppStore";
import type { Point } from "@/types/api";

const RADIUS_KM = 1;

export default function App() {
  const [pendingSpot, setPendingSpot] = useState<Point | null>(null);
  const [isConfirmOpen, setIsConfirmOpen] = useState(false);
  const [isConfirming, setIsConfirming] = useState(false);
  const [tileProvider, setTileProvider] = useState<TileProvider>("openstreetmap");
  const [isDetailsOpen, setIsDetailsOpen] = useState(() => {
    if (typeof window === "undefined") {
      return false;
    }
    return window.innerWidth >= 1024;
  });
  const [isHeaderCollapsed, setIsHeaderCollapsed] = useState(() => {
    if (typeof window === "undefined") {
      return false;
    }
    return window.innerWidth < 768;
  });

  const { t, i18n } = useTranslation();
  const locale = i18n.language === "fr" ? "fr-FR" : "en-US";
  const distanceFormatter = useMemo(
    () =>
      new Intl.NumberFormat(locale, {
        minimumFractionDigits: 2,
        maximumFractionDigits: 2,
      }),
    [locale]
  );

  const tileOptions = useMemo(
    () => [
      { value: "openstreetmap" as TileProvider, label: t("map.tiles.openstreetmap") },
      { value: "mapbox" as TileProvider, label: t("map.tiles.mapbox") },
    ],
    [t]
  );

  const userLocation = useAppStore(state => state.userLocation);
  const locationError = useAppStore(state => state.locationError);
  const isRequestingLocation = useAppStore(state => state.isRequestingLocation);
  const { refresh: refreshLocation } = useUserLocation();

  const {
    status,
    error,
    submitPoint,
    fetchSnapshot,
    selectVisibleDensity,
    selectVisiblePoints,
    selectVisibleLatestByUser,
    myLatestPoint,
    lastUpdated,
  } = useHotspotFeed({ userLocation: userLocation ?? null });

  const visibleDensity = useMemo(
    () => selectVisibleDensity(userLocation ?? null),
    [selectVisibleDensity, userLocation]
  );

  const visiblePoints = useMemo(() => selectVisiblePoints(userLocation ?? null), [selectVisiblePoints, userLocation]);

  const visibleLatestByUser = useMemo(
    () => selectVisibleLatestByUser(userLocation ?? null),
    [selectVisibleLatestByUser, userLocation]
  );

  const localTotals = useMemo(() => {
    const uniqueUsers = new Set<string>();
    visibleLatestByUser.forEach(point => uniqueUsers.add(point.userKey));
    return { points: visiblePoints.length, contributors: uniqueUsers.size };
  }, [visibleLatestByUser, visiblePoints]);

  const myVisibleSignal = useMemo(() => {
    if (!myLatestPoint) {
      return null;
    }
    if (userLocation && distanceInKm(userLocation, myLatestPoint.signalLocation) > RADIUS_KM) {
      return null;
    }
    return myLatestPoint;
  }, [myLatestPoint, userLocation]);

  const statusLabel = t(`status.${status}`);
  const lastUpdatedLabel = lastUpdated ? formatRelativeTime(lastUpdated, locale) : t("common.never");
  const isLoading = status === "loading";
  const isPosting = status === "posting";
  const isRefreshing = status === "refreshing";
  const hasLocation = Boolean(userLocation);
  const showLocationCta = !hasLocation || Boolean(locationError);

  const translatedLocationError = locationError ? t(locationError) : null;
  const locationHint = translatedLocationError
    ? translatedLocationError
    : hasLocation
      ? t("location.hint.showing", { radius: RADIUS_KM })
      : isRequestingLocation
        ? t("location.hint.requesting")
        : t("location.hint.allow");

  const { mapContainerRef, focusOn, fitToHeat } = useLeafletHeatmap({
    heatCells: visibleDensity,
    userLocation: userLocation ?? null,
    onRequestSpot: position => {
      setPendingSpot(position);
      setIsConfirmOpen(true);
    },
    tileProvider,
  });

  const { toast } = useToast();

  useEffect(() => {
    if (!error) {
      return;
    }
    const description = error.detail ?? t(error.key, error.values ?? {});
    toast({
      variant: "destructive",
      title: t("errors.title"),
      description,
      duration: 6000,
    });
  }, [error, t, toast]);

  const handleConfirmSignal = useCallback(async () => {
    if (!pendingSpot) {
      return;
    }
    setIsConfirming(true);
    const result = await submitPoint(pendingSpot);
    setIsConfirming(false);
    if (result.success) {
      setIsConfirmOpen(false);
      setPendingSpot(null);
    }
  }, [pendingSpot, submitPoint]);

  const handleRefresh = useCallback(() => {
    fetchSnapshot().catch(() => undefined);
  }, [fetchSnapshot]);

  const handleFocusHeat = useCallback(() => {
    fitToHeat();
  }, [fitToHeat]);

  const handleLocateUser = useCallback(() => {
    if (userLocation) {
      focusOn(userLocation, 14);
    } else {
      refreshLocation();
    }
  }, [focusOn, refreshLocation, userLocation]);

  const handleFocusMySignal = useCallback(() => {
    if (myVisibleSignal) {
      focusOn({ lat: myVisibleSignal.signalLocation.lat, lng: myVisibleSignal.signalLocation.lng }, 15);
    }
  }, [focusOn, myVisibleSignal]);

  const handleManualReport = useCallback(() => {
    if (!userLocation) {
      return;
    }
    setPendingSpot(userLocation);
    setIsConfirmOpen(true);
  }, [userLocation]);

  const dangerCells = useMemo(
    () =>
      [...visibleDensity]
        .sort((a, b) => b.intensity - a.intensity)
        .slice(0, 5)
        .map((cell, index) => {
          const coordinates = t("common.coordinates", {
            lat: formatCoordinate(cell.lat, locale),
            lng: formatCoordinate(cell.lng, locale),
          });
          const distanceLabel = userLocation
            ? `${distanceFormatter.format(distanceInKm(userLocation, cell))} km`
            : null;
          return {
            id: `${cell.lat}-${cell.lng}-${index}`,
            title: t("hotspots.itemTitle", { index: index + 1 }),
            subtitle:
              distanceLabel !== null
                ? t("hotspots.itemSubtitleWithDistance", { distance: distanceLabel, coordinates })
                : t("hotspots.itemSubtitle", { coordinates }),
            intensity: cell.intensity,
            onFocus: () => focusOn({ lat: cell.lat, lng: cell.lng }, 15),
          };
        }),
    [visibleDensity, userLocation, focusOn, distanceFormatter, t, locale]
  );

  const recentActivity = useMemo(
    () =>
      [...visiblePoints]
        .sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime())
        .slice(0, 8)
        .map(point => {
          const coordinates = t("common.coordinates", {
            lat: formatCoordinate(point.signalLocation.lat, locale),
            lng: formatCoordinate(point.signalLocation.lng, locale),
          });
          const distanceLabel = userLocation
            ? t("activityItem.distance", {
                distance: `${distanceFormatter.format(distanceInKm(userLocation, point.signalLocation))} km`,
              })
            : formatTimestamp(point.createdAt, locale);
          return {
            id: point.id,
            title: coordinates,
            subtitle: t("activityItem.user", { id: point.userKey.slice(0, 4).toUpperCase() }),
            timestampLabel: formatRelativeTime(point.createdAt, locale),
            distanceLabel,
            onFocus: () => focusOn({ lat: point.signalLocation.lat, lng: point.signalLocation.lng }, 15),
          };
        }),
    [visiblePoints, userLocation, focusOn, distanceFormatter, t, locale]
  );

  const confirmationLat = pendingSpot ? formatCoordinate(pendingSpot.lat, locale) : "--";
  const confirmationLng = pendingSpot ? formatCoordinate(pendingSpot.lng, locale) : "--";
  const isDialogDisabled = !pendingSpot || isConfirming;
  const detailsToggleLabel = isDetailsOpen ? t("details.close") : t("details.open");
  const detailsPanelClassName = cn(
    "pointer-events-auto fixed inset-x-0 bottom-0 z-40 flex max-h-[85vh] w-full flex-col overflow-hidden rounded-t-3xl border border-border/70 bg-background/95 shadow-2xl backdrop-blur transition-transform duration-300 sm:left-auto sm:right-6 sm:top-24 sm:bottom-6 sm:max-h-[calc(100vh-8rem)] sm:w-[min(380px,calc(100vw-4rem))] sm:rounded-3xl",
    isDetailsOpen ? "translate-y-0 sm:translate-x-0" : "translate-y-[calc(100%+1rem)] sm:translate-x-[calc(100%+2rem)]"
  );

  return (
    <>
      <div className="relative min-h-screen w-full overflow-hidden bg-background text-foreground">
        <MapViewport
          containerRef={mapContainerRef}
          isPosting={isPosting || isConfirming}
          isLoading={isLoading}
          confirmationHint={isConfirmOpen ? t("map.confirmationHint") : null}
          className="min-h-screen"
        />

        <div className="pointer-events-none absolute inset-0 flex flex-col">
          <div className="flex items-start justify-between gap-3 p-4 sm:p-6">
            <div className="pointer-events-auto">
              <AppHeader
                status={status}
                statusLabel={statusLabel}
                lastUpdatedLabel={lastUpdatedLabel}
                onRefresh={handleRefresh}
                onFocusHeat={handleFocusHeat}
                onLocateUser={handleLocateUser}
                onFocusMySignal={handleFocusMySignal}
                disableRefresh={isLoading || isRefreshing || isPosting}
                disableHeat={visibleDensity.length === 0}
                disableLocate={!hasLocation}
                disableMySignal={!myVisibleSignal}
                collapsed={isHeaderCollapsed}
                onToggleCollapse={() => setIsHeaderCollapsed(prev => !prev)}
              />
            </div>
            <div className="pointer-events-auto hidden sm:flex">
              <Button
                variant="secondary"
                size="icon"
                onClick={() => setIsDetailsOpen(prev => !prev)}
                aria-label={detailsToggleLabel}
                aria-expanded={isDetailsOpen}
                className="h-11 w-11 rounded-full border border-border/60 bg-background/80 shadow-lg backdrop-blur hover:bg-background"
              >
                {isDetailsOpen ? <PanelRightClose className="h-4 w-4" /> : <PanelRightOpen className="h-4 w-4" />}
              </Button>
            </div>
          </div>
        </div>

        {!isDetailsOpen && (
          <div className="pointer-events-auto fixed bottom-4 right-4 z-30 sm:hidden">
            <Button
              variant="secondary"
              size="sm"
              onClick={() => setIsDetailsOpen(true)}
              aria-label={detailsToggleLabel}
              className="flex items-center gap-2 rounded-full border border-border/60 bg-background/85 px-4 py-2 text-xs font-semibold uppercase tracking-wide shadow-lg backdrop-blur"
            >
              <Menu className="h-4 w-4" />
              <span>{t("details.open")}</span>
            </Button>
          </div>
        )}

        <aside
          className={detailsPanelClassName}
          role="complementary"
          aria-label={t("details.title")}
          aria-hidden={!isDetailsOpen}
        >
          <header className="flex items-center justify-between gap-2 border-b border-border/60 bg-background/80 px-4 py-3 backdrop-blur">
            <div className="flex flex-col">
              <span className="text-sm font-semibold">{t("details.title")}</span>
              <span className="text-xs text-muted-foreground">{t("details.description")}</span>
            </div>
            <Button
              variant="ghost"
              size="icon"
              onClick={() => setIsDetailsOpen(false)}
              aria-label={t("details.close")}
              className="h-9 w-9 rounded-full border border-border/60 bg-muted/60 backdrop-blur hover:bg-muted"
            >
              <PanelRightClose className="h-4 w-4" />
            </Button>
          </header>
          <ScrollArea className="flex-1">
            <div className="flex flex-col gap-4 p-4 pb-6">
              <div className="rounded-2xl border border-border/60 bg-muted/40 p-4 shadow-sm">
                <div className="flex items-start gap-3">
                  <span className="flex h-10 w-10 items-center justify-center rounded-2xl border border-border/60 bg-background/80 text-primary">
                    <Layers className="h-5 w-5" />
                  </span>
                  <div className="flex flex-1 flex-col">
                    <span className="text-sm font-semibold">{t("map.tiles.title")}</span>
                    <span className="text-xs text-muted-foreground">{t("map.tiles.subtitle")}</span>
                  </div>
                </div>
                <div className="mt-3 flex flex-wrap gap-2">
                  {tileOptions.map(option => (
                    <Button
                      key={option.value}
                      type="button"
                      variant={tileProvider === option.value ? "default" : "outline"}
                      size="sm"
                      onClick={() => setTileProvider(option.value)}
                      className={cn(
                        "rounded-full border border-border/60 px-4 py-1 text-xs font-medium transition-colors",
                        tileProvider === option.value
                          ? "shadow-sm"
                          : "bg-background/80 text-muted-foreground hover:bg-background"
                      )}
                    >
                      {option.label}
                    </Button>
                  ))}
                </div>
              </div>

              <OverviewPanel
                nearbySignals={localTotals.points}
                uniqueContributors={localTotals.contributors}
                lastUpdatedLabel={lastUpdatedLabel}
                mySignalLabel={myVisibleSignal ? formatRelativeTime(myVisibleSignal.createdAt, locale) : null}
                error={error}
                onReport={handleManualReport}
                onRetry={handleRefresh}
                isPosting={isPosting || isConfirming}
                locationHint={locationHint}
                showLocationCta={showLocationCta}
                disableReport={!hasLocation}
              />
              <HotspotStatsPanel
                hasLocation={hasLocation}
                radiusKm={RADIUS_KM}
                locationHint={locationHint}
                cells={dangerCells}
              />
              <ActivityPanel items={recentActivity} emptyMessage={t("activity.empty")} />
            </div>
          </ScrollArea>
        </aside>

        <AlertDialog
          open={isConfirmOpen}
          onOpenChange={nextOpen => {
            setIsConfirmOpen(nextOpen);
            if (!nextOpen) {
              setPendingSpot(null);
              setIsConfirming(false);
            }
          }}
        >
          <AlertDialogContent>
            <AlertDialogHeader>
              <AlertDialogTitle>{t("dialog.confirmSignal.title")}</AlertDialogTitle>
              <AlertDialogDescription>{t("dialog.confirmSignal.description")}</AlertDialogDescription>
            </AlertDialogHeader>
            <div className="rounded-2xl border border-border/60 bg-muted/40 p-4 text-sm">
              <div className="flex items-center justify-between">
                <span className="text-muted-foreground">{t("dialog.confirmSignal.latitude")}</span>
                <span className="font-medium text-foreground">{confirmationLat}°</span>
              </div>
              <div className="mt-3 flex items-center justify-between">
                <span className="text-muted-foreground">{t("dialog.confirmSignal.longitude")}</span>
                <span className="font-medium text-foreground">{confirmationLng}°</span>
              </div>
              <p className="mt-4 text-xs text-muted-foreground">
                {t("dialog.confirmSignal.reach", { radius: RADIUS_KM })}
              </p>
            </div>
            <AlertDialogFooter>
              <AlertDialogCancel disabled={isConfirming}>{t("dialog.confirmSignal.cancel")}</AlertDialogCancel>
              <AlertDialogAction onClick={handleConfirmSignal} disabled={isDialogDisabled}>
                {isConfirming ? t("dialog.confirmSignal.sending") : t("dialog.confirmSignal.confirm")}
              </AlertDialogAction>
            </AlertDialogFooter>
          </AlertDialogContent>
        </AlertDialog>
      </div>
      <Toaster />
    </>
  );
}
