import { Texture, Assets } from "pixi.js";
import { useEffect, useState, useMemo, useRef } from "react";
import { useTransform } from "./transformContext";
import { lerp, lerpAngle } from "../../utils/animationUtils";

const basePath = new URL(
  "../../assets/tramPosition/Tram Base.svg",
  import.meta.url
).href;
const tramPath = new URL("../../assets/tramPosition/Tram.svg", import.meta.url)
  .href;

const LERP_SPEED = 0.1; // Скорость интерполяции (10% каждый кадр)

// Функция для проверки расстояния до ближайшей точки маршрута
const getDistanceToPath = (
  point: { x: number; y: number },
  pathPoints: { x: number; y: 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.x - p1.x) * (p2.x - p1.x) + (point.y - 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.x - projectedX) ** 2 + (point.y - projectedY) ** 2
    );
    if (dist < minDistance) {
      minDistance = dist;
    }
  }

  return minDistance;
};

// Функция для проверки расстояния до пройденной части маршрута
const getDistanceToPassedPath = (
  point: { x: number; y: number },
  pathPoints: { x: number; y: number }[],
  passedSegmentIndex: number
) => {
  if (!pathPoints || pathPoints.length < 2 || passedSegmentIndex < 0)
    return Infinity;

  let minDistance = Infinity;

  // Проверяем только пройденную часть (до passedSegmentIndex включительно)
  for (
    let i = 0;
    i <= Math.min(passedSegmentIndex, pathPoints.length - 2);
    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.x - p1.x) * (p2.x - p1.x) + (point.y - 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.x - projectedX) ** 2 + (point.y - projectedY) ** 2
    );
    if (dist < minDistance) {
      minDistance = dist;
    }
  }

  return minDistance;
};

// Функция для проверки расстояния до ближайшей станции
const getDistanceToStations = (
  point: { x: number; y: number },
  stations: {
    longitude: number;
    latitude: number;
    offset_x?: number;
    offset_y?: number;
  }[],
  _debug: boolean = false
) => {
  if (!stations || stations.length === 0) {
    return Infinity;
  }

  let minDistance = Infinity;

  for (const station of stations) {
    // Рассчитываем позицию текста станции с учетом смещений (как в Station.tsx)
    const DEFAULT_LABEL_OFFSET_X = 25;
    const DEFAULT_LABEL_OFFSET_Y = 0;

    const labelOffsetX =
      station.offset_x === 0 && station.offset_y === 0
        ? DEFAULT_LABEL_OFFSET_X
        : (station.offset_x || 0) / 3;
    const labelOffsetY =
      station.offset_x === 0 && station.offset_y === 0
        ? DEFAULT_LABEL_OFFSET_Y
        : (station.offset_y || 0) / 3;

    const textBlockPositionX = station.longitude + labelOffsetX;
    const textBlockPositionY = station.latitude + labelOffsetY;

    // Вычисляем расстояние до позиции текста станции (не до центра станции)
    const dist = Math.sqrt(
      (point.x - textBlockPositionX) ** 2 + (point.y - textBlockPositionY) ** 2
    );

    if (dist < minDistance) {
      minDistance = dist;
    }
  }

  return minDistance;
};

// Функция для поиска оптимального угла поворота метки относительно трамвая
const findOptimalAngle = (
  tramX: number,
  tramY: number,
  pathPoints: { x: number; y: number }[],
  stations: {
    longitude: number;
    latitude: number;
    offset_x?: number;
    offset_y?: number;
  }[],
  passedSegmentIndex: number,
  scale: number
) => {
  const testRadiusInMapCoords = 100 / scale; // Радиус в координатах карты
  const minSafeDistanceToPath = 60; // Минимальное безопасное расстояние до пути в пикселях
  const minSafeDistanceToPassedPath = 60; // Минимальное безопасное расстояние до пройденной части в пикселях
  const minSafeDistanceToStation = 50; // Минимальное безопасное расстояние до станции в пикселях

  let bestAngle = 0;
  let bestScore = Infinity; // Ищем минимальный вес
  const segmentWeights: { angle: number; weight: number; distances: any }[] =
    [];

  // Проверяем 12 углов (каждые 30 градусов)
  for (let i = 0; i < 12; i++) {
    const testAngle = (i * Math.PI * 2) / 12;
    const testX = tramX + Math.cos(testAngle) * testRadiusInMapCoords;
    const testY = tramY + Math.sin(testAngle) * testRadiusInMapCoords;

    const distanceToPath =
      getDistanceToPath({ x: testX, y: testY }, pathPoints) * scale; // В пикселях
    const distanceToPassedPath =
      getDistanceToPassedPath(
        { x: testX, y: testY },
        pathPoints,
        passedSegmentIndex
      ) * scale; // В пикселях
    const distanceToStation =
      getDistanceToStations({ x: testX, y: testY }, stations, false) * scale; // В пикселях с отладкой

    // Вычисляем вес для этого угла (чем меньше расстояние, тем больше вес)
    let weight = 0;

    // Путь - вес 100
    if (distanceToPath < minSafeDistanceToPath) {
      weight += 100 * (1 - distanceToPath / minSafeDistanceToPath);
    }

    // Текст прошедшей станции - вес 10
    if (distanceToPassedPath < minSafeDistanceToPassedPath) {
      weight += 10 * (1 - distanceToPassedPath / minSafeDistanceToPassedPath);
    }

    // Текст следующей станции - вес 1000
    if (distanceToStation < minSafeDistanceToStation) {
      weight += 1000 * (1 - distanceToStation / minSafeDistanceToStation);
    }

    segmentWeights.push({
      angle: testAngle,
      weight: Math.round(weight * 10) / 10, // Округляем для читаемости
      distances: {
        path: Math.round(distanceToPath),
        passedPath: Math.round(distanceToPassedPath),
        station: Math.round(distanceToStation),
      },
    });

    if (weight < bestScore) {
      bestScore = weight;
      bestAngle = testAngle;
    }
  }

  // Если несколько сегментов имеют одинаковый минимальный вес,
  // выбираем тот, который максимально удален от препятствий
  const minWeightSegments = segmentWeights.filter(
    (s) => s.weight === bestScore
  );
  if (minWeightSegments.length > 1) {
    // Из сегментов с минимальным весом выбираем тот, который максимально удален от препятствий
    let bestDistanceSum = -1;
    for (const segment of minWeightSegments) {
      const distanceSum =
        segment.distances.path +
        segment.distances.passedPath +
        segment.distances.station;
      if (distanceSum > bestDistanceSum) {
        bestDistanceSum = distanceSum;
        bestAngle = segment.angle;
      }
    }
  }

  return { bestAngle, segmentWeights };
};

export function TramIcon({
  x,
  y,
  angle,
  pathPoints = [],
  stations = [],
  passedSegmentIndex = -1,
}: {
  x: number;
  y: number;
  angle: number;
  pathPoints?: { x: number; y: number }[];
  stations?: {
    longitude: number;
    latitude: number;
    offset_x?: number;
    offset_y?: number;
  }[];
  passedSegmentIndex?: number;
}) {
  const { scale } = useTransform();

  // Находим оптимальный угол поворота метки относительно трамвая
  const optimalAngle = useMemo(
    () =>
      findOptimalAngle(x, y, pathPoints, stations, passedSegmentIndex, scale)
        .bestAngle,
    [x, y, pathPoints, stations, passedSegmentIndex, scale]
  );

  // Состояние для плавной анимации позиции и углов (как в HTML файле)
  const [smoothPosition, setSmoothPosition] = useState({ x, y });
  const [smoothOptimalAngle, setSmoothOptimalAngle] = useState(optimalAngle);
  const [smoothTramAngle, setSmoothTramAngle] = useState(angle);
  const animationRef = useRef<number | undefined>(undefined);

  // Плавная анимация позиции и углов (логика из HTML файла)
  useEffect(() => {
    const animate = () => {
      // Анимируем позицию (как в HTML файле)
      setSmoothPosition((prev) => {
        const newX = lerp(prev.x, x, LERP_SPEED);
        const newY = lerp(prev.y, y, LERP_SPEED);
        return {
          x: Math.abs(newX - x) < 0.1 ? x : newX,
          y: Math.abs(newY - y) < 0.1 ? y : newY,
        };
      });

      // Анимируем оптимальный угол
      setSmoothOptimalAngle((prev) => {
        const newAngle = lerpAngle(prev, optimalAngle, LERP_SPEED);
        return Math.abs(newAngle - optimalAngle) < 0.01
          ? optimalAngle
          : newAngle;
      });

      // Анимируем угол трамвая
      setSmoothTramAngle((prev) => {
        const newAngle = lerpAngle(prev, angle, LERP_SPEED);
        return Math.abs(newAngle - angle) < 0.01 ? angle : newAngle;
      });

      // Продолжаем анимацию, если что-то еще не достигло цели
      if (
        Math.abs(smoothPosition.x - x) > 0.1 ||
        Math.abs(smoothPosition.y - y) > 0.1 ||
        Math.abs(smoothOptimalAngle - optimalAngle) > 0.01 ||
        Math.abs(smoothTramAngle - angle) > 0.01
      ) {
        animationRef.current = requestAnimationFrame(animate);
      }
    };

    animationRef.current = requestAnimationFrame(animate);

    return () => {
      if (animationRef.current !== undefined) {
        cancelAnimationFrame(animationRef.current);
      }
    };
  }, [
    x,
    y,
    optimalAngle,
    angle,
    smoothPosition,
    smoothOptimalAngle,
    smoothTramAngle,
  ]);

  // Обычные размеры без увеличения
  const backgroundWidth = 111 / scale;
  const backgroundHeight = 82 / scale;
  const tramWidth = 31 / scale;
  const tramHeight = 52 / scale;

  const [baseTexture, setBaseTexture] = useState<Texture | null>(null);
  const [tramTexture, setTramTexture] = useState<Texture | null>(null);

  useEffect(() => {
    Assets.load(basePath).then(setBaseTexture).catch(console.error);
    Assets.load(tramPath).then(setTramTexture).catch(console.error);
  }, []);

  if (!baseTexture || !tramTexture) return null;

  return (
    <pixiContainer x={smoothPosition.x} y={smoothPosition.y}>
      {/* вращающийся контейнер с плавным оптимальным углом */}
      <pixiContainer rotation={smoothOptimalAngle + Math.PI}>
        <pixiSprite
          texture={baseTexture}
          anchor={{ x: 1, y: 0.5 }}
          width={backgroundWidth > 53.7 ? backgroundWidth : 53.7}
          height={backgroundHeight > 39.68 ? backgroundHeight : 39.68}
        />

        {/* контейнер иконки трамвая с плавным поворотом направления движения */}
        <pixiContainer
          x={
            backgroundWidth > 53.7
              ? -backgroundWidth / 1.42
              : -backgroundWidth / 0.98
          }
          y={0}
        >
          <pixiSprite
            texture={tramTexture}
            anchor={0.5}
            rotation={-smoothOptimalAngle - Math.PI}
            width={tramWidth}
            height={tramHeight}
          />
        </pixiContainer>
      </pixiContainer>
    </pixiContainer>
  );
}
