import { useMemo } from "react";

import type { TFunction } from "i18next";

import { distanceInKm, formatCoordinate, formatRelativeTime, formatTimestamp } from "@/lib/utils";
import type { Point, Signal, SignalDensityCell } from "@/types/api";

type DangerCell = {
  id: string;
  title: string;
  subtitle: string;
  intensity: number;
  onFocus: () => void;
};

type ActivityItem = {
  id: string;
  title: string;
  subtitle: string;
  timestampLabel: string;
  distanceLabel: string;
  onFocus: () => void;
};

interface UseFeedDerivationsArgs {
  visibleDensity: SignalDensityCell[];
  visiblePoints: Signal[];
  visibleLatestByUser: Signal[];
  userLocation: Point | null;
  focusOn: (position: Point, zoom?: number) => void;
  distanceFormatter: Intl.NumberFormat;
  t: TFunction;
  locale: string;
  myLatestPoint: Signal | null;
  radiusKm: number;
}

export function useFeedDerivations({
  visibleDensity,
  visiblePoints,
  visibleLatestByUser,
  userLocation,
  focusOn,
  distanceFormatter,
  t,
  locale,
  myLatestPoint,
  radiusKm,
}: UseFeedDerivationsArgs) {
  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) > radiusKm) {
      return null;
    }
    return myLatestPoint;
  }, [myLatestPoint, userLocation, radiusKm]);

  const dangerCells: DangerCell[] = 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: ActivityItem[] = 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: string = userLocation
            ? (t("activityItem.distance", {
                distance: `${distanceFormatter.format(distanceInKm(userLocation, point.signalLocation))} km`,
              }) as string)
            : 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]
  );

  return { localTotals, myVisibleSignal, dangerCells, recentActivity };
}
