import Taro from '@tarojs/taro';
import { useEffect, useRef, useState } from 'react';
import { getDistance } from '../../../../utils/Robotaxi-public-method';
import { TripStatus } from '../../../constants/trip-status';
import {
  ANDROID_ROUTE_POINT_LIMIT,
  DEFAULT_ROUTE_POINT_LIMIT,
  Deps,
  ROUTE_ERASE_BREAK_DISTANCE_FACTOR,
  ROUTE_ERASE_BREAK_DISTANCE_METERS,
  ROUTE_ERASE_MAX_DISTANCE_METERS,
  ROUTE_POLYLINE_BASE_ID,
  WALKING_POLYLINE_ID_OFFSET,
} from './use-route-manager.shared';
import { emitDisplayRoutePoints } from './route-display-channel';

/** Polyline 渲染 Hook 入参。 */
type UsePolylineRenderParams = {
  /** 路线管理依赖。 */
  deps: Deps;
  /** 当前选中的路线索引。 */
  selectedRouteIndex: number;
  /** 全量可选路线点集合。 */
  allRoutePoints: any[][];
};

/** Polyline 渲染 Hook 返回值。 */
type UsePolylineRenderResult = {
  /** 地图折线集合。 */
  polyline: any[];
  /** 设置地图折线集合。 */
  setPolyline: React.Dispatch<React.SetStateAction<any[]>>;
  /** 主路线点集合。 */
  routePoints: any[];
  /** 设置主路线点集合。 */
  setRoutePoints: React.Dispatch<React.SetStateAction<any[]>>;
  /** 步行路线点集合。 */
  walkingPoints: any[];
  /** 设置步行路线点集合。 */
  setWalkingPoints: React.Dispatch<React.SetStateAction<any[]>>;
  /** 步行时长。 */
  walkingTime: number;
  /** 设置步行时长。 */
  setWalkingTime: React.Dispatch<React.SetStateAction<number>>;
  /** 路线请求签名引用。 */
  polylineKeyRef: React.MutableRefObject<string>;
  /** 最近一次路线起点引用。 */
  lastRoutePointRef: React.MutableRefObject<{ latitude: number; longitude: number } | null>;
  /** 最近一次路线更新时间引用。 */
  lastRouteUpdateAtRef: React.MutableRefObject<number>;
  /** 最近一次 polyline 更新时间引用。 */
  lastPolylineUpdateAtRef: React.MutableRefObject<number>;
  /** 当前完整订单路线引用。 */
  currentFullRouteRef: React.MutableRefObject<any[]>;
  /** 最近一次擦除索引引用。 */
  lastErasedIndexRef: React.MutableRefObject<number>;
  /** 订单路线初始化引用。 */
  orderRouteInitializedRef: React.MutableRefObject<boolean>;
  /** 应用路线点。 */
  applyRoutePoints: (points: any[]) => boolean;
  /** 路线点降采样。 */
  reducePoints: (points: any[], maxCount: number) => any[];
  /** 重置路线运行时状态。 */
  resetRouteRuntimeState: () => void;
  /** 擦除已行驶路线。 */
  erasePassedRouteSegments: (newPoints: any[], servedPoints?: any[]) => void;
  /** 构建 polyline 签名。 */
  buildPolylineKey: (displayRoutePoints: any[]) => string;
  /** 构建 polyline 数据。 */
  buildPolylineLines: (displayRoutePoints: any[]) => any[];
};

const PASSED_ROUTE_POLYLINE_ID = 1999; // 已走过路线浅色折线 ID
const FIRST_ROUTE_ERASE_READY_DELAY_MS = 120;

/** 统一获取路线降采样上限。 */
const resolveRoutePointLimit = (isAndroid: boolean) => (
  isAndroid ? ANDROID_ROUTE_POINT_LIMIT : DEFAULT_ROUTE_POINT_LIMIT
);

/**
 * 管理路线点、擦线与 polyline 渲染。
 */
export default function usePolylineRender(params: UsePolylineRenderParams): UsePolylineRenderResult {
  const { deps, selectedRouteIndex, allRoutePoints } = params;

  /** 地图折线集合。 */
  const [polyline, setPolyline] = useState<any[]>([]);
  /** 主路线点集合。 */
  const [routePoints, setRoutePoints] = useState<any[]>([]);
  /** 步行路线点集合。 */
  const [walkingPoints, setWalkingPoints] = useState<any[]>([]);
  /** 步行时长。 */
  const [walkingTime, setWalkingTime] = useState<number>(0);

  /** 路线渲染签名引用。 */
  const polylineKeyRef = useRef<string>('');
  /** 最近一次路线起点引用。 */
  const lastRoutePointRef = useRef<{ latitude: number; longitude: number } | null>(null);
  /** 最近一次路线更新时间引用。 */
  const lastRouteUpdateAtRef = useRef<number>(0);
  /** 最近一次 polyline 更新时间引用。 */
  const lastPolylineUpdateAtRef = useRef<number>(0);
  /** 当前完整订单路线引用。 */
  const currentFullRouteRef = useRef<any[]>([]);
  /** 最近一次擦除索引引用。 */
  const lastErasedIndexRef = useRef<number>(0);
  /** 订单路线初始化引用。 */
  const orderRouteInitializedRef = useRef<boolean>(false);
  /** 主路线首次进入原生地图后的擦线就绪标记。 */
  const routeEraseReadyRef = useRef<boolean>(false);
  /** 待执行的最新擦线路径。 */
  const pendingRouteEraseRef = useRef<any[] | null>(null);
  /** 首次擦线延时器。 */
  const routeEraseReadyTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);

  /**
   * 清理首次擦线延时器，避免旧任务串到下一条路线。
   */
  const clearRouteEraseReadyTimer = () => {
    if (routeEraseReadyTimerRef.current) {
      clearTimeout(routeEraseReadyTimerRef.current);
      routeEraseReadyTimerRef.current = null;
    }
  };

  /**
   * 同步擦线后的剩余路线点，保持 React 与原生图层一致。
   */
  const applyErasedRoutePoints = (newPoints: any[]) => {
    currentFullRouteRef.current = [...newPoints];
    lastErasedIndexRef.current = 0;
    applyRoutePoints([...newPoints]);
  };

  /**
   * 应用路线点并同步运行时引用。
   */
  const applyRoutePoints = (points: any[]) => {
    if (Array.isArray(points) && points.length > 0) {
      const firstPoint = points[0];
      const nextLatitude = Number(firstPoint?.latitude);
      const nextLongitude = Number(firstPoint?.longitude);
      const now = Date.now();
      if (Number.isFinite(nextLatitude) && Number.isFinite(nextLongitude)) {
        lastRoutePointRef.current = { latitude: nextLatitude, longitude: nextLongitude };
        lastRouteUpdateAtRef.current = now;
      } else {
        lastRoutePointRef.current = null;
        lastRouteUpdateAtRef.current = 0;
      }
      setRoutePoints(points);
      return true;
    }
    lastRoutePointRef.current = null;
    lastRouteUpdateAtRef.current = 0;
    setRoutePoints([]);
    return true;
  };

  /**
   * 对路线点做降采样，减少渲染压力。
   */
  const reducePoints = (points: any[], maxCount: number) => {
    if (!Array.isArray(points) || points.length <= maxCount) {
      return points;
    }
    const step = Math.ceil(points.length / maxCount);
    const reducedPoints: any[] = [];
    for (let index = 0; index < points.length; index += step) {
      reducedPoints.push(points[index]);
    }
    const lastPoint = points[points.length - 1];
    if (reducedPoints[reducedPoints.length - 1] !== lastPoint) {
      reducedPoints.push(lastPoint);
    }
    return reducedPoints;
  };

  /**
   * 重置路线运行时状态。
   */
  const resetRouteRuntimeState = () => {
    setRoutePoints([]);
    setPolyline([]);
    polylineKeyRef.current = '';
    lastPolylineUpdateAtRef.current = 0;
    lastRoutePointRef.current = null;
    lastRouteUpdateAtRef.current = 0;
    currentFullRouteRef.current = [];
    lastErasedIndexRef.current = 0;
    orderRouteInitializedRef.current = false;
    routeEraseReadyRef.current = false;
    pendingRouteEraseRef.current = null;
    clearRouteEraseReadyTimer();
  };

  /**
   * 擦除已行驶路段，并同步 React 中的路线点。
   */
  const erasePassedRouteSegments = (newPoints: any[], _servedPoints: any[] = []) => {
    const oldPoints = currentFullRouteRef.current;
    if (!oldPoints?.length || !newPoints?.length) {
      return;
    }
    const boundaryPoint = newPoints[0];
    if (
      !boundaryPoint
      || typeof boundaryPoint.latitude !== 'number'
      || typeof boundaryPoint.longitude !== 'number'
    ) {
      return;
    }

    let bestMatchIndex = -1;
    let bestDistance = Infinity;
    const startIndex = lastErasedIndexRef.current;
    for (let index = startIndex; index < oldPoints.length; index += 1) {
      const distance = getDistance(
        oldPoints[index].latitude,
        oldPoints[index].longitude,
        boundaryPoint.latitude,
        boundaryPoint.longitude
      );
      if (distance < bestDistance) {
        bestDistance = distance;
        bestMatchIndex = index;
      }
      if (
        distance > bestDistance * ROUTE_ERASE_BREAK_DISTANCE_FACTOR
        && bestDistance < ROUTE_ERASE_BREAK_DISTANCE_METERS
      ) {
        break;
      }
    }

    const executeRouteErase = () => {
      if (bestMatchIndex >= startIndex && bestDistance < ROUTE_ERASE_MAX_DISTANCE_METERS) {
        Taro.createMapContext('map').eraseLines({
          lines: [{
            id: ROUTE_POLYLINE_BASE_ID,
            index: Math.max(0, bestMatchIndex - 1),
            point: {
              latitude: boundaryPoint.latitude,
              longitude: boundaryPoint.longitude,
            },
            clear: true
          }]
        });
      }
      applyErasedRoutePoints(newPoints);
    };

    if (process.env.TARO_ENV !== 'weapp' || routeEraseReadyRef.current) {
      executeRouteErase();
      return;
    }
    pendingRouteEraseRef.current = [...newPoints];
    clearRouteEraseReadyTimer();
    const elapsedSincePolylineUpdate = lastPolylineUpdateAtRef.current > 0
      ? Math.max(0, Date.now() - lastPolylineUpdateAtRef.current)
      : 0;
    const waitMs = lastPolylineUpdateAtRef.current > 0
      ? Math.max(0, FIRST_ROUTE_ERASE_READY_DELAY_MS - elapsedSincePolylineUpdate)
      : FIRST_ROUTE_ERASE_READY_DELAY_MS;
    routeEraseReadyTimerRef.current = setTimeout(() => {
      routeEraseReadyTimerRef.current = null;
      routeEraseReadyRef.current = true;
      if (!pendingRouteEraseRef.current) {
        return;
      }
      const latestPoints = pendingRouteEraseRef.current;
      pendingRouteEraseRef.current = null;
      erasePassedRouteSegments(latestPoints);
    }, waitMs);
  };

  /**
   * 获取当前用于渲染的主路线点。
   */
  const getDisplayRoutePoints = () => {
    const isEraseMode = [TripStatus.VehicleApproaching, TripStatus.InService].includes(deps.tripStatus);
    return isEraseMode
      ? routePoints
      : reducePoints(routePoints, resolveRoutePointLimit(deps.isAndroid));
  };

  /**
   * 获取修改目的地预览态下的已走过路线点。
   */
  const getPassedRoutePoints = () => {
    const shouldShowPassedRoute = deps.tripStatus === TripStatus.InService
      && deps.allowSelectableRoutes
      && Array.isArray(deps.vehicleMoveAlongPoints)
      && deps.vehicleMoveAlongPoints.length > 1;
    if (!shouldShowPassedRoute) {
      return [];
    }
    return reducePoints(deps.vehicleMoveAlongPoints || [], resolveRoutePointLimit(deps.isAndroid));
  };

  /**
   * 构建 polyline 渲染签名，避免重复 setState。
   */
  const buildPolylineKey = (displayRoutePoints: any[]) => {
    const passedRoutePoints = getPassedRoutePoints();
    const lastRoutePoint = displayRoutePoints[displayRoutePoints.length - 1];
    const lastPassedRoutePoint = passedRoutePoints[passedRoutePoints.length - 1];
    const lastWalkingPoint = walkingPoints[walkingPoints.length - 1];
    return [
      deps.shouldShowRoute ? 1 : 0,
      deps.statusRule.showWalking ? 1 : 0,
      displayRoutePoints.length,
      passedRoutePoints.length,
      walkingPoints.length,
      lastRoutePoint?.latitude ?? '',
      lastRoutePoint?.longitude ?? '',
      lastPassedRoutePoint?.latitude ?? '',
      lastPassedRoutePoint?.longitude ?? '',
      lastWalkingPoint?.latitude ?? '',
      lastWalkingPoint?.longitude ?? '',
      allRoutePoints.length,
      selectedRouteIndex
    ].join('|');
  };

  /**
   * 构建地图 polyline 数据。
   */
  const buildPolylineLines = (displayRoutePoints: any[]) => {
    const lines: any[] = [];
    const passedRoutePoints = getPassedRoutePoints();
    if (passedRoutePoints.length > 1) {
      lines.push({
        id: PASSED_ROUTE_POLYLINE_ID,
        points: passedRoutePoints,
        color: '#D6D9DC',
        width: 10,
        clickable: false,
        dottedLine: false,
        arrowLine: false,
      });
    }
    if (deps.shouldShowRoute && deps.allowSelectableRoutes && allRoutePoints.length > 1) {
      allRoutePoints.forEach((points, index) => {
        if (!points?.length) {
          return;
        }
        if (index !== selectedRouteIndex) {
          lines.push({
            id: ROUTE_POLYLINE_BASE_ID + index,
            points: reducePoints(points, resolveRoutePointLimit(deps.isAndroid)),
            color: '#BED6CA',
            width: 10,
            clickable: true,
            dottedLine: false,
            arrowLine: true,
          });
        }
      });

      const selectedPoints = allRoutePoints[selectedRouteIndex];
      if (Array.isArray(selectedPoints) && selectedPoints.length > 0) {
        lines.push({
          id: ROUTE_POLYLINE_BASE_ID + selectedRouteIndex,
          points: displayRoutePoints,
          color: '#59B688',
          width: 8,
          borderColor: '#3D8F66',
          borderWidth: 1,
          clickable: true,
          dottedLine: false,
          arrowLine: true,
        });
      }
    } else if (deps.shouldShowRoute && displayRoutePoints.length > 0) {
      lines.push({
        id: ROUTE_POLYLINE_BASE_ID,
        points: displayRoutePoints,
        color: '#59B688',
        width: 8,
        borderColor: '#3D8F66',
        borderWidth: 1,
        clickable: true,
        dottedLine: false,
        arrowLine: true,
      });
    }

    if (deps.statusRule.showWalking && walkingPoints.length > 0) {
      lines.push({
        id: WALKING_POLYLINE_ID_OFFSET + allRoutePoints.length,
        points: walkingPoints,
        color: '#DFB369',
        width: deps.isAndroid ? 5 : 8,
        dottedLine: true,
        arrowLine: false,
      });
    }
    return lines;
  };

  useEffect(() => {
    const displayRoutePoints = getDisplayRoutePoints();
    const nextPolylineKey = buildPolylineKey(displayRoutePoints);
    if (nextPolylineKey === polylineKeyRef.current) {
      return;
    }
    polylineKeyRef.current = nextPolylineKey;

    // 将剩余路线点推送给订阅方（如自动缩放），无论是否需要绘制路线都推送
    emitDisplayRoutePoints(displayRoutePoints);
    const shouldDrawRoute = deps.shouldShowRoute && displayRoutePoints.length > 0;
    const shouldDrawWalking = deps.statusRule.showWalking && walkingPoints.length > 0;
    if (shouldDrawRoute || shouldDrawWalking) {
      if (lastPolylineUpdateAtRef.current === 0) {
        routeEraseReadyRef.current = false;
        pendingRouteEraseRef.current = null;
        clearRouteEraseReadyTimer();
      }
      const polylineLines = buildPolylineLines(displayRoutePoints);
      setPolyline(polylineLines);
      lastPolylineUpdateAtRef.current = Date.now();
      return;
    }
    if (![TripStatus.TripFinished, TripStatus.PaymentSuccess].includes(deps.tripStatus)) {
      setPolyline([]);
    }
    lastPolylineUpdateAtRef.current = 0;
    routeEraseReadyRef.current = false;
    pendingRouteEraseRef.current = null;
    clearRouteEraseReadyTimer();
  }, [
    allRoutePoints,
    deps.allowSelectableRoutes,
    deps.isAndroid,
    deps.shouldShowRoute,
    deps.statusRule.showWalking,
    deps.tripStatus,
    deps.vehicleMoveAlongPoints,
    routePoints,
    selectedRouteIndex,
    walkingPoints
  ]);

  useEffect(() => () => {
    clearRouteEraseReadyTimer();
  }, []);

  return {
    polyline,
    setPolyline,
    routePoints,
    setRoutePoints,
    walkingPoints,
    setWalkingPoints,
    walkingTime,
    setWalkingTime,
    polylineKeyRef,
    lastRoutePointRef,
    lastRouteUpdateAtRef,
    lastPolylineUpdateAtRef,
    currentFullRouteRef,
    lastErasedIndexRef,
    orderRouteInitializedRef,
    applyRoutePoints,
    reducePoints,
    resetRouteRuntimeState,
    erasePassedRouteSegments,
    buildPolylineKey,
    buildPolylineLines
  };
}
