// SightsLayer.tsx
import { Graphics, Assets, Texture, TextStyle } from "pixi.js";
import { useCallback, useEffect, useState, useMemo } from "react";
import { useTransform } from "./transformContext";
import { SightData } from "./types";
import sightIcon from "../../assets/images/sight.svg";
import { useGeolocationStore } from "../../stores"; // Импортируем useGeolocationStore

const BASE_ICON_SIZE = 30;
const CLUSTER_RADIUS_BASE = 10;

type Cluster = {
  id: string;
  longitude: number;
  latitude: number;
  count: number;
  sights: SightData[];
};

type PointItem = { type: "point"; id: string; data: SightData };
type ClusterItem = { type: "cluster"; id: string; data: Cluster };
type ClusteredItem = PointItem | ClusterItem;

const getDistance = (
  p1: { longitude: number; latitude: number },
  p2: { longitude: number; latitude: number }
) => {
  return Math.sqrt(
    Math.pow(p1.longitude - p2.longitude, 2) +
      Math.pow(p1.latitude - p2.latitude, 2)
  );
};

const getDistanceFromPointToPath = (
  point: { longitude: number; latitude: number },
  pathPoints: { x: number; y: number }[]
): number => {
  if (!pathPoints || pathPoints.length < 2) {
    return Infinity;
  }

  let minDistance = Infinity;

  for (let i = 0; i < pathPoints.length - 1; i++) {
    const p1 = pathPoints[i];
    const p2 = pathPoints[i + 1];

    const lineLengthSq = (p2.x - p1.x) ** 2 + (p2.y - p1.y) ** 2;
    if (lineLengthSq === 0) continue;

    const t =
      ((point.longitude - p1.x) * (p2.x - p1.x) +
        (point.latitude - p1.y) * (p2.y - p1.y)) /
      lineLengthSq;
    const projectionT = Math.max(0, Math.min(1, t));

    const projectedX = p1.x + projectionT * (p2.x - p1.x);
    const projectedY = p1.y + projectionT * (p2.y - p1.y);

    const dist = Math.sqrt(
      (point.longitude - projectedX) ** 2 + (point.latitude - projectedY) ** 2
    );
    minDistance = Math.min(minDistance, dist);
  }
  return minDistance;
};

const useSightClustering = (
  sights: SightData[],
  distanceThreshold: number,
  pathPoints: { x: number; y: number }[]
): ClusteredItem[] => {
  return useMemo(() => {
    const unclusteredSights: (SightData & { visited?: boolean })[] = sights.map(
      (s) => ({ ...s })
    );
    const clusteredResult: ClusteredItem[] = [];

    for (const sight of unclusteredSights) {
      if (sight.visited) {
        continue;
      }

      const clusterSights: SightData[] = [];
      const queue = [sight];
      sight.visited = true;

      while (queue.length > 0 && clusterSights.length < 4) {
        const current = queue.shift()!;
        clusterSights.push(current);

        for (const potentialNeighbor of unclusteredSights) {
          if (
            !potentialNeighbor.visited &&
            clusterSights.length < 4 &&
            getDistance(current, potentialNeighbor) < distanceThreshold
          ) {
            potentialNeighbor.visited = true;
            queue.push(potentialNeighbor);
          }
        }
      }

      if (clusterSights.length > 1) {
        let furthestSight: SightData | null = null;
        let maxDistanceToPath = -1;

        for (const s of clusterSights) {
          const dist = getDistanceFromPointToPath(s, pathPoints);
          if (dist > maxDistanceToPath) {
            maxDistanceToPath = dist;
            furthestSight = s;
          }
        }

        const count = clusterSights.length;
        const longitude = furthestSight
          ? furthestSight.longitude
          : clusterSights.reduce((sum, s) => sum + s.longitude, 0) / count;
        const latitude = furthestSight
          ? furthestSight.latitude
          : clusterSights.reduce((sum, s) => sum + s.latitude, 0) / count;

        const id = `cluster-${clusterSights[0].id}`;
        clusteredResult.push({
          type: "cluster",
          id,
          data: { id, count, longitude, latitude, sights: clusterSights },
        });
      } else {
        const singleSight = clusterSights[0];
        clusteredResult.push({
          type: "point",
          id: String(singleSight.id),
          data: singleSight,
        });
      }
    }
    return clusteredResult;
  }, [sights, distanceThreshold, pathPoints]);
};

// Изменяем пропсы для SingleSight, чтобы он мог передавать ID при тапе
function SingleSight({
  sight,
  onSightClick,
}: {
  readonly sight: SightData;
  onSightClick: (sightId: string) => void;
}) {
  useTransform();
  const [texture, setTexture] = useState<Texture>(Texture.EMPTY);
  const store = useGeolocationStore();
  const { setIsGovernorWidgetOpen } = store;
  useEffect(() => {
    Assets.load(sightIcon).then(setTexture).catch(console.error);
  }, []);

  const handlePointerTap = useCallback(() => {
    setIsGovernorWidgetOpen(false);
    onSightClick(String(sight.id)); // Передаем ID выбранной достопримечательности
  }, [sight.id, onSightClick]);

  if (texture === Texture.EMPTY) {
    return null;
  }

  const dynamicSize = BASE_ICON_SIZE;

  return (
    <pixiSprite
      texture={texture}
      x={sight.longitude}
      y={sight.latitude}
      width={dynamicSize}
      height={dynamicSize}
      anchor={0.5}
      eventMode="static"
      onPointerTap={handlePointerTap}
    />
  );
}

// Добавляем onSightSelectedInCluster в пропсы
function SightCluster({
  cluster,
  onClusterToggle,
  isExpanded,
  onSightSelectedInCluster,
}: {
  readonly cluster: Cluster;
  onClusterToggle: (clusterId: string | null) => void;
  isExpanded: boolean;
  onSightSelectedInCluster: (sightId: string) => void;
}) {
  const store = useGeolocationStore();
  const { setIsGovernorWidgetOpen } = store;
  useTransform();
  const radius = CLUSTER_RADIUS_BASE;
  const [texture, setTexture] = useState<Texture>(Texture.EMPTY);
  const fontSize = 14;

  useEffect(() => {
    Assets.load(sightIcon).then(setTexture).catch(console.error);
  }, []);

  const clusterTextStyle = useMemo(
    () =>
      new TextStyle({
        fill: "white",
        fontSize: fontSize,
        fontWeight: "bold",
      }),
    [fontSize]
  );

  const handleClusterTap = useCallback(() => {
    onClusterToggle(isExpanded ? null : cluster.id);
  }, [cluster.id, cluster.count, isExpanded, onClusterToggle]);

  const handleSightSelect = useCallback(
    (sightId: string) => {
      setIsGovernorWidgetOpen(false);
      onSightSelectedInCluster(sightId); // Передаем выбранный ID наверх
      onClusterToggle(null); // Закрываем кластер после выбора достопримечательности
    },
    [onClusterToggle, onSightSelectedInCluster, setIsGovernorWidgetOpen]
  ); // Добавляем onSightSelectedInCluster в зависимости

  const drawClusterGraphics = useCallback(
    (g: Graphics) => {
      g.clear();
      g.beginFill(0x896f58);
      g.drawCircle(0, 0, radius);
      g.endFill();
    },
    [radius]
  );

  const drawExpandedClusterBackground = useCallback((g: Graphics) => {
    g.clear();
    const expandedRadius = BASE_ICON_SIZE * 2;
    g.beginFill(0x896f58, 0.3);
    g.lineStyle(2, 0x896f58, 1);
    g.drawCircle(0, 0, expandedRadius);
    g.endFill();
  }, []);

  const handleBackgroundTap = useCallback(() => {
    onClusterToggle(null); // Закрываем кластер при клике по фону
  }, [cluster.id, onClusterToggle]);

  if (texture === Texture.EMPTY) {
    return null;
  }

  const dynamicSize = BASE_ICON_SIZE;
  const offsetX = dynamicSize / 2;
  const offsetY = -dynamicSize / 2;

  const getPositionForSight = (index: number, total: number) => {
    const angle = (index / total) * Math.PI * 2;
    const distance = BASE_ICON_SIZE * 1.2;
    return {
      x: distance * Math.cos(angle),
      y: distance * Math.sin(angle),
    };
  };

  return (
    <pixiContainer x={cluster.longitude} y={cluster.latitude}>
      {isExpanded && (
        <pixiGraphics
          draw={drawExpandedClusterBackground}
          eventMode="static"
          onPointerTap={handleBackgroundTap}
        />
      )}

      {!isExpanded ? (
        <>
          <pixiSprite
            texture={texture}
            x={0}
            y={0}
            width={dynamicSize}
            height={dynamicSize}
            anchor={0.5}
            eventMode="static"
            onPointerTap={handleClusterTap}
          />
          <pixiGraphics draw={drawClusterGraphics} x={offsetX} y={offsetY} />
          <pixiText
            text={String(cluster.count)}
            x={offsetX}
            y={offsetY}
            anchor={0.5}
            style={clusterTextStyle}
            resolution={4}
          />
        </>
      ) : (
        <>
          {cluster.sights.map((sight, index) => {
            const pos = getPositionForSight(index, cluster.sights.length);
            return (
              <pixiSprite
                key={sight.id}
                texture={texture}
                x={pos.x}
                y={pos.y}
                width={dynamicSize}
                height={dynamicSize}
                anchor={0.5}
                eventMode="static"
                onPointerTap={() => handleSightSelect(String(sight.id))}
              />
            );
          })}
        </>
      )}
    </pixiContainer>
  );
}

interface SightsLayerProps {
  sights: SightData[];
  pathPoints: { x: number; y: number }[];
}

export function SightsLayer({
  sights,
  pathPoints,
}: Readonly<SightsLayerProps>) {
  useTransform();
  const distanceThreshold = BASE_ICON_SIZE * 3;

  const store = useGeolocationStore(); // Получаем доступ к MobX хранилищу
  const {
    setSelectedSightId,
    setIsManualSelection,
    setIsRightWidgetSelectorOpen,
  } = store; // Получаем нужные экшены

  const items = useSightClustering(sights, distanceThreshold, pathPoints);

  const [activeClusterId, setActiveClusterId] = useState<string | null>(null);

  const handleClusterToggle = useCallback((clusterId: string | null) => {
    setActiveClusterId(clusterId);
  }, []);

  const handleSightSelected = useCallback(
    (sightId: string) => {
      setSelectedSightId(sightId);
      setIsManualSelection(true);
      setIsRightWidgetSelectorOpen(false); // Закрываем селектор правого виджета при клике по достопримечательности
      // Закрываем виджет губернатора при выборе достопримечательности
      store.closeGovernorModal();
    },
    [
      setSelectedSightId,
      setIsManualSelection,
      setIsRightWidgetSelectorOpen,
      store,
    ]
  );

  return (
    <>
      {items.map((item) => {
        if (item.type === "cluster") {
          return (
            <SightCluster
              key={item.id}
              cluster={item.data}
              onClusterToggle={handleClusterToggle}
              isExpanded={activeClusterId === item.id}
              onSightSelectedInCluster={handleSightSelected}
            />
          );
        }
        return (
          <SingleSight
            key={item.id}
            sight={item.data}
            onSightClick={handleSightSelected}
          />
        );
      })}
    </>
  );
}
