import { useEffect, useRef } from 'react';
import Taro from '@tarojs/taro';
import wsManager from '../../../../utils/websocket';
import { queryVehicleByOrderId } from '../../../api/begin-route';
import { clearOrderTripStorage, safeParse } from '../../../../utils/Robotaxi-public-method';
import { normalizeDistanceKm, normalizeDurationSeconds } from '../../../../robotaxi/utils/format';

type UseWebSocketEventsDeps = {
    tripStatusRef: any;
    orderId: string;
    setOrderId: (orderId: string) => void;
    setTripStatus: (status: number) => void;
    setVehicleInfo: (vehicle: any) => void;
    vehicleInfo: any;
    setPriceUpdateVersion: (updater: (v: number) => number) => void;
    setFinishCountdownEnabled: (value: boolean) => void;
    setShowAnnouncementsPopup: (value: boolean) => void;
    setRoutePoints: (points: any[]) => void;
    setPolyline: (lines: any[]) => void;
    polylineKeyRef: any;
    lastPolylineUpdateAtRef: any;
    lastRoutePointRef: any;
    lastRouteUpdateAtRef: any;
    lastVehiclePointRef: any;
    lastVehicleUpdateAtRef: any;
    currentFullRouteRef: any;
    lastErasedIndexRef: any;
    orderRouteInitializedRef: any;
    setCancelType: (value: number) => void;
    setShowCancelPopup: (value: boolean) => void;
    checkAndShowPassengerNotice: () => void;
    setVehicleDirection: (value: number) => void;
    setVehicleMoveAlongPoints: (points: any[]) => void;
    setRouteDistance: (value: any) => void;
    setRouteDuration: (value: number) => void;
    erasePassedRouteSegments: (points: any[], servedPoints?: any[]) => void;
    applyRoutePoints: (points: any[]) => boolean;
    updateVehicleLocationThrottled: (lat: number, lng: number, force?: boolean) => void;
};

const resolveOrderId = (payload: any, fallbackOrderId: string) =>
    payload?.content?.orderId || payload?.orderId || fallbackOrderId || Taro.getStorageSync('orderId');

const isSameOrder = (incomingOrderId: string, currentOrderId: string) => {
    if (!incomingOrderId || !currentOrderId) return true;
    return String(incomingOrderId) === String(currentOrderId);
};

const resetRouteRuntimeState = (deps: UseWebSocketEventsDeps) => {
    deps.setRoutePoints([]);
    deps.setPolyline([]);
    deps.setVehicleMoveAlongPoints([]);
    deps.polylineKeyRef.current = '';
    deps.lastPolylineUpdateAtRef.current = 0;
    deps.lastRoutePointRef.current = null;
    deps.lastRouteUpdateAtRef.current = 0;
    deps.lastVehiclePointRef.current = null;
    deps.lastVehicleUpdateAtRef.current = 0;
    deps.currentFullRouteRef.current = [];
    deps.lastErasedIndexRef.current = 0;
    deps.orderRouteInitializedRef.current = false;
};

const syncTripStatus = (payload: any, deps: UseWebSocketEventsDeps) => {
    const mappedTripStatus = payload?.tripStatus;
    if (typeof mappedTripStatus !== 'number') {
        return null;
    }
    const currentTripStatus = Number(deps.tripStatusRef.current);
    // 行程进行关键态不允许被回退，避免 4/6 被延迟状态覆盖导致路线链路重置
    if ([4, 6].includes(currentTripStatus) && mappedTripStatus < currentTripStatus) {
        return currentTripStatus;
    }
    if (currentTripStatus === mappedTripStatus) {
        return mappedTripStatus;
    }
    deps.setTripStatus(mappedTripStatus);
    deps.tripStatusRef.current = mappedTripStatus;
    Taro.setStorageSync('tripStatus', mappedTripStatus);
    return mappedTripStatus;
};

const syncVehicleInfo = (
    effectiveOrderId: string,
    deps: UseWebSocketEventsDeps,
    lastFetchedVehicleOrderIdRef: any
) => {
    if (!effectiveOrderId) return;
    const vehicleInfoEmpty =
        !deps.vehicleInfo ||
        (!deps.vehicleInfo.plateNumber && !deps.vehicleInfo.vehicleCode && !deps.vehicleInfo.vehicleColor && !deps.vehicleInfo.vehiclePictures);
    const shouldFetchVehicle =
        lastFetchedVehicleOrderIdRef.current !== effectiveOrderId &&
        (vehicleInfoEmpty || deps.orderId !== effectiveOrderId);

    if (deps.orderId !== effectiveOrderId) {
        deps.setOrderId(effectiveOrderId);
    }
    if (!shouldFetchVehicle) return;
    lastFetchedVehicleOrderIdRef.current = effectiveOrderId;
    queryVehicleByOrderId({ orderId: effectiveOrderId })
        .then((res: any) => {
            deps.setVehicleInfo(res);
        })
        .catch(() => { });
};

const handleCancelPopupPush = (payload: any, changeStatusOld: number, deps: UseWebSocketEventsDeps) => {
    if (!payload?.showCancelPopup) return;
    if (changeStatusOld === 4 || changeStatusOld === 5) {
        deps.setOrderId('');
        clearOrderTripStorage();
        Taro.removeStorageSync('pickupEndTime');
        Taro.removeStorageSync('waitingTimerStartAt');
        Taro.removeStorageSync('waitingTimerElapsed');
        deps.setCancelType(4);
    } else {
        deps.setCancelType(5);
    }
    deps.setTripStatus(10);
    deps.setShowCancelPopup(true);
};

const handleStatusSideEffects = (mappedTripStatus: number | null, changeStatusOld: number, deps: UseWebSocketEventsDeps) => {
    if (mappedTripStatus === 6) {
        deps.setShowAnnouncementsPopup(false);
    }
    if (mappedTripStatus === 5 && changeStatusOld !== 5) {
        resetRouteRuntimeState(deps);
    }
    if (mappedTripStatus === 4 && changeStatusOld !== 4) {
        resetRouteRuntimeState(deps);
    }
};

const handleOrderStatusPayload = (
    payload: any,
    deps: UseWebSocketEventsDeps,
    lastFetchedVehicleOrderIdRef: any
) => {
    const changeStatusOld = deps.tripStatusRef.current;
    const currentOrderId = deps.orderId || Taro.getStorageSync('orderId');
    const incomingOrderId = payload?.content?.orderId || payload?.orderId;
    if (!isSameOrder(incomingOrderId, currentOrderId)) {
        return;
    }

    const mappedTripStatus = syncTripStatus(payload, deps);
    const effectiveOrderId = resolveOrderId(payload, currentOrderId);
    syncVehicleInfo(effectiveOrderId, deps, lastFetchedVehicleOrderIdRef);
    handleStatusSideEffects(mappedTripStatus, changeStatusOld, deps);
    handleCancelPopupPush(payload, changeStatusOld, deps);

    if (payload?.showPassengerNotice) {
        deps.checkAndShowPassengerNotice();
    }
};

const updateRouteSummary = (payload: any, deps: UseWebSocketEventsDeps) => {
    const direction = Number(payload?.direction);
    if (Number.isFinite(direction)) {
        deps.setVehicleDirection(((direction % 360) + 360) % 360);
    }
    const route = safeParse(payload?.content?.route, {});
    const distanceKm = normalizeDistanceKm(Number(route?.distance));
    if (distanceKm !== null) {
        deps.setRouteDistance(distanceKm);
    }
    const durationSeconds = normalizeDurationSeconds(Number(route?.duration));
    if (durationSeconds !== null) {
        deps.setRouteDuration(durationSeconds);
    }
};

const resolveVehiclePoint = (points: any[], servedPoints: any[] = []) => {
    const servedLastPoint = Array.isArray(servedPoints) && servedPoints.length > 0
        ? servedPoints[servedPoints.length - 1]
        : null;
    if (servedLastPoint && typeof servedLastPoint.latitude === 'number' && typeof servedLastPoint.longitude === 'number') {
        return servedLastPoint;
    }
    const firstPoint = points?.[0];
    if (firstPoint && typeof firstPoint.latitude === 'number' && typeof firstPoint.longitude === 'number') {
        return firstPoint;
    }
    return null;
};

const resolveVehiclePointForErase = (points: any[], servedPoints: any[] = []) => {
    const firstPoint = points?.[0];
    if (firstPoint && typeof firstPoint.latitude === 'number' && typeof firstPoint.longitude === 'number') {
        return firstPoint;
    }
    return resolveVehiclePoint(points, servedPoints);
};

const syncVehiclePointWithRoute = (points: any[], deps: UseWebSocketEventsDeps, servedPoints: any[] = []) => {
    const targetPoint = resolveVehiclePoint(points, servedPoints);
    if (!targetPoint) {
        return;
    }
    const currentTripStatus = Number(deps.tripStatusRef.current);
    if (currentTripStatus === 7) {
        const lastPoint = deps.lastVehiclePointRef.current;
        const latDiff = Math.abs(Number(lastPoint?.latitude || 0) - targetPoint.latitude);
        const lngDiff = Math.abs(Number(lastPoint?.longitude || 0) - targetPoint.longitude);
        const almostSamePoint = latDiff < 0.000003 && lngDiff < 0.000003;
        if (almostSamePoint) {
            return;
        }
    }
    deps.updateVehicleLocationThrottled(targetPoint.latitude, targetPoint.longitude, true);
};

const handleEraseRouteStatus = (points: any[], servedPoints: any[], deps: UseWebSocketEventsDeps) => {
    const targetPoint = resolveVehiclePointForErase(points, servedPoints);
    if (targetPoint) {
        deps.updateVehicleLocationThrottled(targetPoint.latitude, targetPoint.longitude, true);
    }
    if (deps.orderRouteInitializedRef.current && deps.currentFullRouteRef.current.length > 0) {
        deps.erasePassedRouteSegments(points);
    } else {
        deps.orderRouteInitializedRef.current = true;
        deps.currentFullRouteRef.current = [...points];
        deps.lastErasedIndexRef.current = 0;
        Taro.nextTick(() => {
            deps.applyRoutePoints(points);
        });
    }
};

const handleNormalRouteStatus = (points: any[], deps: UseWebSocketEventsDeps, servedPoints: any[] = []) => {
    Taro.nextTick(() => {
        const updated = deps.applyRoutePoints(points);
        if (!updated) return;
        if (![4, 5, 6, 7].includes(deps.tripStatusRef.current)) return;
        syncVehiclePointWithRoute(points, deps, servedPoints);
    });
};

const handleForceFullRouteRedraw = (points: any[], deps: UseWebSocketEventsDeps, servedPoints: any[] = []) => {
    deps.setRoutePoints([]);
    deps.setPolyline([]);
    deps.orderRouteInitializedRef.current = false;
    deps.currentFullRouteRef.current = [];
    deps.lastErasedIndexRef.current = 0;
    deps.polylineKeyRef.current = '';
    deps.lastPolylineUpdateAtRef.current = 0;
    deps.lastRoutePointRef.current = null;
    deps.lastRouteUpdateAtRef.current = 0;

    Taro.nextTick(() => {
        deps.orderRouteInitializedRef.current = points.length > 0;
        deps.currentFullRouteRef.current = [...points];
        deps.lastErasedIndexRef.current = 0;
        deps.applyRoutePoints(points);
        if (points.length > 0) {
            syncVehiclePointWithRoute(points, deps, servedPoints);
        }
    });
};

const handleOrderRoutePayload = (payload: any, deps: UseWebSocketEventsDeps) => {
    const points = payload?.points || [];
    const servedPoints = Array.isArray(payload?.servedPoints) ? payload.servedPoints : [];
    const forceFullRedraw = payload?.forceFullRedraw === true;
    const currentTripStatus = Number(deps.tripStatusRef.current);
    updateRouteSummary(payload, deps);
    // 行程结束态仅更新概要信息，不再消费路线点，避免视口反复重算造成跳动
    if ([8, 9].includes(currentTripStatus)) {
        return;
    }
    if ([4, 6].includes(currentTripStatus)) {
        deps.setVehicleMoveAlongPoints(servedPoints);
    }
    if (forceFullRedraw) {
        handleForceFullRouteRedraw(points, deps, servedPoints);
        return;
    }
    const isEraseStatus = ![7, 8, 9].includes(currentTripStatus);
    if (isEraseStatus) {
        handleEraseRouteStatus(points, servedPoints, deps);
        return;
    }
    handleNormalRouteStatus(points, deps, servedPoints);
};

export default function useWebSocketEvents(deps: UseWebSocketEventsDeps) {
    // 持有最新依赖，避免渲染过程反复解绑/重绑监听
    const depsRef = useRef(deps);
    useEffect(() => {
        depsRef.current = deps;
    }, [deps]);

    // 各事件是否已绑定标记
    const authSuccessBound = useRef(false);
    const messageBound = useRef(false);
    const orderStatusBound = useRef(false);
    const orderRouteBound = useRef(false);
    const openTrunkBound = useRef(false);
    const orderUpdatePriceBound = useRef(false);
    const orderReassignBound = useRef(false);

    const authSuccessHandlerRef = useRef<(data: any) => void>();
    const messageHandlerRef = useRef<(data: any) => void>();
    const orderStatusHandlerRef = useRef<(data: any) => void>();
    const orderRouteHandlerRef = useRef<(data: any) => void>();
    const openTrunkHandlerRef = useRef<(data: any) => void>();
    const orderUpdatePriceHandlerRef = useRef<(data: any) => void>();
    const orderReassignHandlerRef = useRef<(data: any) => void>();
    const socketOpenHandlerRef = useRef<(() => void) | null>(null);
    const lastFetchedVehicleOrderIdRef = useRef<string | null>(null);

    // 仅初始化一次事件处理器与解绑逻辑
    useEffect(() => {
        authSuccessHandlerRef.current = () => {
            if (!messageBound.current && messageHandlerRef.current) {
                wsManager.on('message', messageHandlerRef.current);
                messageBound.current = true;
            }
        };
        messageHandlerRef.current = (data) => {
            console.log('ws message:', data);
        };
        openTrunkHandlerRef.current = (payload) => {
            const currentDeps = depsRef.current;
            const isOpen = Number(payload?.isOpen);
            if (isOpen === 1) {
                currentDeps.setFinishCountdownEnabled(true);
            }
        };
        orderUpdatePriceHandlerRef.current = (payload) => {
            const currentDeps = depsRef.current;
            const incomingOrderId = payload?.orderId || payload?.content?.orderId || Taro.getStorageSync('orderId');
            const currentOrderId = currentDeps.orderId || Taro.getStorageSync('orderId');
            if (!isSameOrder(incomingOrderId, currentOrderId)) {
                return;
            }
            currentDeps.setPriceUpdateVersion((v: number) => v + 1);
        };
        orderReassignHandlerRef.current = (payload) => {
            const currentDeps = depsRef.current;
            const incomingOrderId = payload?.orderId || payload?.content?.orderId || Taro.getStorageSync('orderId');
            const currentOrderId = currentDeps.orderId || Taro.getStorageSync('orderId');
            if (!isSameOrder(incomingOrderId, currentOrderId)) {
                return;
            }
            lastFetchedVehicleOrderIdRef.current = null;
            queryVehicleByOrderId({ orderId: currentOrderId })
                .then((res: any) => {
                    currentDeps.setVehicleInfo(res);
                })
                .catch(() => { });
        };
        orderStatusHandlerRef.current = (payload) => {
            handleOrderStatusPayload(payload, depsRef.current, lastFetchedVehicleOrderIdRef);
        };
        orderRouteHandlerRef.current = (payload) => {
            handleOrderRoutePayload(payload, depsRef.current);
        };
        // 处理重进页面时 useDidShow 先于 handler 初始化的场景，确保已连接状态下也能完成监听绑定
        if (wsManager.isConnectedStatus()) {
            bindSocketListeners();
        }

        return () => {
            if (authSuccessBound.current && authSuccessHandlerRef.current) {
                wsManager.off('auth_success', authSuccessHandlerRef.current);
                authSuccessBound.current = false;
            }
            if (messageBound.current && messageHandlerRef.current) {
                wsManager.off('message', messageHandlerRef.current);
                messageBound.current = false;
            }
            if (orderStatusBound.current && orderStatusHandlerRef.current) {
                wsManager.off('order_status', orderStatusHandlerRef.current);
                orderStatusBound.current = false;
            }
            if (orderRouteBound.current && orderRouteHandlerRef.current) {
                wsManager.off('order_route', orderRouteHandlerRef.current);
                orderRouteBound.current = false;
            }
            if (openTrunkBound.current && openTrunkHandlerRef.current) {
                wsManager.off('open_trunk', openTrunkHandlerRef.current);
                openTrunkBound.current = false;
            }
            if (orderUpdatePriceBound.current && orderUpdatePriceHandlerRef.current) {
                wsManager.off('order_update_price', orderUpdatePriceHandlerRef.current);
                orderUpdatePriceBound.current = false;
            }
            if (orderReassignBound.current && orderReassignHandlerRef.current) {
                wsManager.off('order_reassign', orderReassignHandlerRef.current);
                orderReassignBound.current = false;
            }
            if (socketOpenHandlerRef.current) {
                wsManager.off('open', socketOpenHandlerRef.current);
                socketOpenHandlerRef.current = null;
            }
        };
    }, []);

    // 绑定业务事件监听
    const bindSocketListeners = () => {
        if (!authSuccessBound.current && authSuccessHandlerRef.current) {
            wsManager.on('auth_success', authSuccessHandlerRef.current);
            authSuccessBound.current = true;
        }
        if (!orderStatusBound.current && orderStatusHandlerRef.current) {
            wsManager.on('order_status', orderStatusHandlerRef.current);
            orderStatusBound.current = true;
        }
        if (!orderRouteBound.current && orderRouteHandlerRef.current) {
            wsManager.on('order_route', orderRouteHandlerRef.current);
            orderRouteBound.current = true;
        }
        if (!openTrunkBound.current && openTrunkHandlerRef.current) {
            wsManager.on('open_trunk', openTrunkHandlerRef.current);
            openTrunkBound.current = true;
        }
        if (!orderUpdatePriceBound.current && orderUpdatePriceHandlerRef.current) {
            wsManager.on('order_update_price', orderUpdatePriceHandlerRef.current);
            orderUpdatePriceBound.current = true;
        }
        if (!orderReassignBound.current && orderReassignHandlerRef.current) {
            wsManager.on('order_reassign', orderReassignHandlerRef.current);
            orderReassignBound.current = true;
        }
    };

    // 确保连接可用并完成监听绑定
    const ensureSocketListeners = (host: string) => {
        if (wsManager.isConnectedStatus()) {
            bindSocketListeners();
            return;
        }
        if (socketOpenHandlerRef.current) {
            wsManager.connect(host);
            return;
        }
        const handleOpen = () => {
            bindSocketListeners();
        };
        socketOpenHandlerRef.current = handleOpen;
        wsManager.on('open', handleOpen);
        wsManager.connect(host);
    };

    return {
        ensureSocketListeners,
        bindSocketListeners
    };
}
