/**
 * 항적조회 전용 상태 관리 스토어
 *
 * 선박 모달 항적조회에서 사용
 * 프로그레스 바 기반 시간 이동 및 선박 위치 계산
 */

import { create } from 'zustand';
import { subscribeWithSelector } from 'zustand/middleware';
import useShipStore from '../../stores/shipStore';

/**
 * 유효한 선명인지 확인
 */
function isValidShipName(name) {
  if (!name) return false;
  const trimmed = name.trim();
  if (!trimmed) return false;
  if (trimmed === '-') return false;
  if (trimmed === 'No Exist Name') return false;
  if (/^\d+$/.test(trimmed)) return false;
  return true;
}

/**
 * 라이브 선박 데이터 가져오기
 * dark 프로젝트의 shipStore.features 기반
 */
function getLiveShipInfo(sigSrcCd, targetId) {
  const { features } = useShipStore.getState();
  const featureKey = `${sigSrcCd}${targetId}`;
  const liveShip = features.get(featureKey);

  const result = { shipName: null, shipKindCode: null, integrationTargetId: null };

  if (liveShip) {
    if (isValidShipName(liveShip.shipName)) {
      result.shipName = liveShip.shipName.trim();
    }
    if (liveShip.signalKindCode && liveShip.signalKindCode.trim()) {
      result.shipKindCode = liveShip.signalKindCode.trim();
    }
    if (liveShip.targetId && liveShip.targetId.includes('_')) {
      result.integrationTargetId = liveShip.targetId;
    }
  }

  return result;
}

/**
 * 항적 데이터에 라이브 선박 정보 병합
 */
function mergeWithLiveData(tracks) {
  return tracks.map(track => {
    const liveInfo = getLiveShipInfo(track.sigSrcCd, track.targetId);
    let updated = { ...track };
    let hasChanges = false;

    if (liveInfo.shipName) {
      if (track.shipName !== liveInfo.shipName) {
        updated.shipName = liveInfo.shipName;
        hasChanges = true;
      }
    } else if (!isValidShipName(track.shipName)) {
      if (track.shipName !== '') {
        updated.shipName = '';
        hasChanges = true;
      }
    }

    if (liveInfo.shipKindCode && track.shipKindCode !== liveInfo.shipKindCode) {
      updated.shipKindCode = liveInfo.shipKindCode;
      hasChanges = true;
    }

    if (liveInfo.integrationTargetId) {
      if (!track.integrationTargetId || track.integrationTargetId !== liveInfo.integrationTargetId) {
        updated.integrationTargetId = liveInfo.integrationTargetId;
        hasChanges = true;
      }
    }

    return hasChanges ? updated : track;
  });
}

/**
 * 두 지점 사이의 선박 위치를 시간 기반으로 보간
 */
function interpolatePosition(p1, p2, t1, t2, currentTime) {
  if (t1 === t2) return p1;
  if (currentTime <= t1) return p1;
  if (currentTime >= t2) return p2;

  const ratio = (currentTime - t1) / (t2 - t1);
  const lon = p1[0] + (p2[0] - p1[0]) * ratio;
  const lat = p1[1] + (p2[1] - p1[1]) * ratio;

  return [lon, lat];
}

/**
 * 두 지점 간의 방향(heading) 계산
 */
function calculateHeading(p1, p2) {
  const [lon1, lat1] = p1;
  const [lon2, lat2] = p2;

  const dx = lon2 - lon1;
  const dy = lat2 - lat1;

  let angle = (Math.atan2(dx, dy) * 180) / Math.PI;
  angle = -angle;
  if (angle < 0) angle += 360;

  return angle;
}

/**
 * 항적조회 스토어
 */
export const useTrackQueryStore = create(subscribeWithSelector((set, get) => ({
  tracks: [],
  disabledVesselIds: new Set(),
  dataStartTime: 0,
  dataEndTime: 0,
  requestedStartTime: 0,
  currentTime: 0,
  isLoading: false,
  error: null,
  showPoints: false,
  showVirtualShip: true,
  hideLiveShips: false,
  showLabels: true,
  isModalMode: false,
  modalSourceId: null,
  highlightedVesselId: null,
  showPlayback: false,

  // 포인트 호버 정보
  hoveredPoint: null,
  hoveredPointPosition: { x: 0, y: 0 },

  /**
   * 항적 데이터 설정
   * 라이브 선박 데이터와 병합하여 선명 정보 보완
   */
  setTracks: (tracks, requestedStartTime, showPlayback = false) => {
    if (tracks.length === 0) {
      set({
        tracks: [],
        dataStartTime: 0,
        dataEndTime: 0,
        requestedStartTime: 0,
        currentTime: 0,
        error: null,
        showPlayback: false,
      });
      return;
    }

    const mergedTracks = mergeWithLiveData(tracks);

    let minTime = Infinity;
    let maxTime = -Infinity;

    mergedTracks.forEach(track => {
      if (track.timestampsMs.length > 0) {
        minTime = Math.min(minTime, track.timestampsMs[0]);
        maxTime = Math.max(maxTime, track.timestampsMs[track.timestampsMs.length - 1]);
      }
    });

    const initialTime =
      requestedStartTime >= minTime && requestedStartTime <= maxTime ? requestedStartTime : minTime;

    set({
      tracks: mergedTracks,
      dataStartTime: minTime,
      dataEndTime: maxTime,
      requestedStartTime,
      currentTime: initialTime,
      error: null,
      showPlayback,
    });
  },

  setCurrentTime: (time) => {
    const { dataStartTime, dataEndTime } = get();
    const clampedTime = Math.max(dataStartTime, Math.min(dataEndTime, time));
    set({ currentTime: clampedTime });
  },

  setProgressByRatio: (ratio) => {
    const { dataStartTime, dataEndTime } = get();
    const clampedRatio = Math.max(0, Math.min(1, ratio));
    const newTime = dataStartTime + (dataEndTime - dataStartTime) * clampedRatio;
    set({ currentTime: newTime });
  },

  setLoading: (loading) => set({ isLoading: loading }),
  setError: (error) => set({ error }),
  setShowPoints: (show) => set({ showPoints: show }),
  setShowVirtualShip: (show) => set({ showVirtualShip: show }),
  setHideLiveShips: (hide) => set({ hideLiveShips: hide }),
  setShowLabels: (show) => set({ showLabels: show }),

  setModalMode: (isModal, sourceId) => {
    set({
      isModalMode: isModal,
      modalSourceId: isModal ? (sourceId || null) : null,
    });
  },

  getModalSourceId: () => get().modalSourceId,

  setHighlightedVesselId: (vesselId) => set({ highlightedVesselId: vesselId }),

  setHoveredPoint: (point, x, y) => set({
    hoveredPoint: point,
    hoveredPointPosition: { x: x || 0, y: y || 0 },
  }),

  clearHoveredPoint: () => set({
    hoveredPoint: null,
    hoveredPointPosition: { x: 0, y: 0 },
  }),

  toggleVesselEnabled: (vesselId) => {
    const { disabledVesselIds } = get();
    const newDisabled = new Set(disabledVesselIds);
    if (newDisabled.has(vesselId)) {
      newDisabled.delete(vesselId);
    } else {
      newDisabled.add(vesselId);
    }
    set({ disabledVesselIds: newDisabled });
  },

  isVesselEnabled: (vesselId) => !get().disabledVesselIds.has(vesselId),

  getEnabledTracks: () => {
    const { tracks, disabledVesselIds } = get();
    return tracks.filter(track => !disabledVesselIds.has(track.vesselId));
  },

  getProgress: () => {
    const { currentTime, dataStartTime, dataEndTime } = get();
    if (dataEndTime === dataStartTime) return 0;
    return ((currentTime - dataStartTime) / (dataEndTime - dataStartTime)) * 100;
  },

  /**
   * 현재 시간의 모든 선박 위치 계산
   * 이진 탐색 + 선형 보간
   */
  getCurrentPositions: () => {
    const { tracks, currentTime, disabledVesselIds } = get();
    const positions = [];

    tracks.forEach(track => {
      if (disabledVesselIds.has(track.vesselId)) return;
      const { timestampsMs, geometry, speeds, vesselId, targetId, sigSrcCd, shipName, shipKindCode, nationalCode } = track;
      if (timestampsMs.length === 0) return;

      const firstTime = timestampsMs[0];
      const lastTime = timestampsMs[timestampsMs.length - 1];

      if (currentTime < firstTime || currentTime > lastTime) return;

      // 이진 탐색
      let left = 0;
      let right = timestampsMs.length - 1;

      while (left < right) {
        const mid = Math.floor((left + right) / 2);
        if (timestampsMs[mid] < currentTime) {
          left = mid + 1;
        } else {
          right = mid;
        }
      }

      const idx1 = Math.max(0, left - 1);
      const idx2 = Math.min(timestampsMs.length - 1, left);

      let position;
      let heading;
      let speed;

      if (idx1 === idx2 || timestampsMs[idx1] === timestampsMs[idx2]) {
        position = geometry[idx1];
        speed = speeds[idx1] || 0;

        if (idx2 < geometry.length - 1) {
          heading = calculateHeading(geometry[idx1], geometry[idx2 + 1]);
        } else if (idx1 > 0) {
          heading = calculateHeading(geometry[idx1 - 1], geometry[idx1]);
        } else {
          heading = 0;
        }
      } else {
        position = interpolatePosition(geometry[idx1], geometry[idx2], timestampsMs[idx1], timestampsMs[idx2], currentTime);
        heading = calculateHeading(geometry[idx1], geometry[idx2]);

        const ratio = (currentTime - timestampsMs[idx1]) / (timestampsMs[idx2] - timestampsMs[idx1]);
        speed = (speeds[idx1] || 0) + ((speeds[idx2] || 0) - (speeds[idx1] || 0)) * ratio;
      }

      positions.push({
        vesselId,
        targetId,
        sigSrcCd,
        shipName,
        shipKindCode,
        nationalCode,
        position,
        heading,
        speed,
        timestamp: currentTime,
      });
    });

    return positions;
  },

  reset: () => {
    set({
      tracks: [],
      disabledVesselIds: new Set(),
      dataStartTime: 0,
      dataEndTime: 0,
      requestedStartTime: 0,
      currentTime: 0,
      isLoading: false,
      error: null,
      showPoints: false,
      showVirtualShip: true,
      hideLiveShips: false,
      showLabels: true,
      isModalMode: false,
      modalSourceId: null,
      highlightedVesselId: null,
      showPlayback: false,
      hoveredPoint: null,
      hoveredPointPosition: { x: 0, y: 0 },
    });
  },
})));

// 편의 셀렉터
export const useTrackQueryTracks = () => useTrackQueryStore(state => state.tracks);
export const useTrackQueryCurrentTime = () => useTrackQueryStore(state => state.currentTime);
export const useTrackQueryIsLoading = () => useTrackQueryStore(state => state.isLoading);
export const useTrackQueryShowPoints = () => useTrackQueryStore(state => state.showPoints);
export const useTrackQueryShowVirtualShip = () => useTrackQueryStore(state => state.showVirtualShip);

export default useTrackQueryStore;
