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

import { useTranslation } from "react-i18next";
import { toast } from "sonner";

import { ConfirmSignalDialog } from "@/components/app/confirm-signal-dialog";
import { HeaderOverlay } from "@/components/app/header-overlay";
import { SidebarPanels } from "@/components/app/sidebar-panels";
import { MapViewport } from "@/components/map/map-viewport";
import { SidebarProvider, Sidebar, SidebarContent, SidebarInset } from "@/components/ui/sidebar";
import { Toaster } from "@/components/ui/sonner";
import { useFeedDerivations } from "@/hooks/use-feed-derivations";
import { useHotspotFeed } from "@/hooks/use-hotsop-feed";
import { useLeafletHeatmap } from "@/hooks/use-leaflet-heatmap";
import { useUserLocation } from "@/hooks/use-user-location";
import { formatCoordinate, formatRelativeTime } from "@/lib/utils";
import { useAppStore } from "@/store/use-app-store";
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 { 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 userLocation = useAppStore(state => state.userLocation);
  const locationError = useAppStore(state => state.locationError);
  const isRequestingLocation = useAppStore(state => state.isRequestingLocation);
  const isDetailsOpen = useAppStore(state => state.isSidebarOpen);
  const setIsDetailsOpen = useAppStore(state => state.setIsSidebarOpen);
  const tileProvider = useAppStore(state => state.tileProvider);
  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 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 { localTotals, myVisibleSignal, dangerCells, recentActivity } = useFeedDerivations({
    visibleDensity,
    visiblePoints,
    visibleLatestByUser,
    userLocation: userLocation ?? null,
    focusOn,
    distanceFormatter,
    t,
    locale,
    myLatestPoint: myLatestPoint ?? null,
    radiusKm: RADIUS_KM,
  });

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

  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 confirmationLat = pendingSpot ? formatCoordinate(pendingSpot.lat, locale) : "--";
  const confirmationLng = pendingSpot ? formatCoordinate(pendingSpot.lng, locale) : "--";
  const isDialogDisabled = !pendingSpot || isConfirming;

  return (
    <>
      <SidebarProvider open={isDetailsOpen} onOpenChange={setIsDetailsOpen}>
        <Sidebar side="left">
          <SidebarContent>
            <SidebarPanels
              localTotals={localTotals}
              lastUpdatedLabel={lastUpdatedLabel}
              myVisibleSignalCreatedAt={myVisibleSignal ? myVisibleSignal.createdAt : null}
              error={error}
              onReport={handleManualReport}
              onRetry={handleRefresh}
              isBusy={isPosting || isConfirming}
              locationHint={locationHint}
              showLocationCta={showLocationCta}
              dangerCells={dangerCells}
              recentActivity={recentActivity}
            />
          </SidebarContent>
        </Sidebar>

        {/* Main content area that automatically accounts for the sidebar gap */}
        <SidebarInset>
          <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"
            />

            <HeaderOverlay
              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}
            />

            <ConfirmSignalDialog
              open={isConfirmOpen}
              onOpenChange={nextOpen => {
                setIsConfirmOpen(nextOpen);
                if (!nextOpen) {
                  setPendingSpot(null);
                  setIsConfirming(false);
                }
              }}
              latitudeLabel={confirmationLat}
              longitudeLabel={confirmationLng}
              radiusKm={RADIUS_KM}
              isConfirming={isConfirming}
              isDisabled={isDialogDisabled}
              onConfirm={handleConfirmSignal}
            />
          </div>
        </SidebarInset>
      </SidebarProvider>
      <Toaster position="bottom-right" />
    </>
  );
}
