/**
 * 재생 항적(Trail) 상태 관리 스토어
 * 참조: mda-react-front/src/tracking/stores/playbackTrailStore.ts
 *
 * 애니메이션 재생 시 선박의 이동 궤적을 반투명 점으로 표시
 * - 시간이 지나면 점 크기 축소, 투명도 증가
 * - 기준 프레임 초과 시 제거
 * - 배속에 따라 maxFrames 동적 조절
 */
import { create } from 'zustand';
import { subscribeWithSelector } from 'zustand/middleware';

// 기본 설정값 (75% 수준으로 조정 - 성능 최적화)
const BASE_MAX_FRAMES = 45; // 기본 프레임 수 (1x 배속 기준)
const MIN_MAX_FRAMES = 25; // 최소 프레임 수
const MAX_MAX_FRAMES = 225; // 최대 프레임 수
const DEFAULT_MAX_POINT_SIZE = 4; // 최대 4px
const DEFAULT_MIN_POINT_SIZE = 1; // 최소 1px

/**
 * 배속에 따른 maxFrames 계산
 * 배속이 빠르면 더 많은 프레임을 유지해서 비슷한 시간 길이의 항적 표시
 * @param {number} playbackSpeed - 재생 배속 (0.5, 1, 2, 4, 8, 16 등)
 * @returns {number} maxFrames
 */
const calculateMaxFrames = (playbackSpeed) => {
  // 배속에 비례하여 프레임 수 증가
  // 1x: 60프레임, 2x: 120프레임, 4x: 240프레임, 0.5x: 30프레임
  const frames = Math.round(BASE_MAX_FRAMES * playbackSpeed);
  return Math.max(MIN_MAX_FRAMES, Math.min(MAX_MAX_FRAMES, frames));
};

/**
 * 재생 항적 스토어
 *
 * @typedef {Object} PlaybackTrailPoint
 * @property {number} lon - 경도
 * @property {number} lat - 위도
 * @property {number} frameIndex - 기록된 프레임 인덱스
 * @property {string} vesselId - 선박 ID
 */
const usePlaybackTrailStore = create(
  subscribeWithSelector((set, get) => ({
    // ========== 상태 ==========

    /** 항적표시 토글 상태 */
    isEnabled: false,

    /** 선박별 항적 포인트 Map (vesselId -> PlaybackTrailPoint[]) */
    trails: new Map(),

    /** 현재 프레임 인덱스 (렌더링마다 증가) */
    frameIndex: 0,

    /** 현재 재생 배속 */
    playbackSpeed: 1,

    /** 유지할 최대 프레임 수 (배속에 따라 동적 계산) */
    maxFrames: BASE_MAX_FRAMES,

    /** 포인트 최대 크기 (px) */
    maxPointSize: DEFAULT_MAX_POINT_SIZE,

    /** 포인트 최소 크기 (px) */
    minPointSize: DEFAULT_MIN_POINT_SIZE,

    // ========== 액션 ==========

    /**
     * 토글 ON/OFF
     * @param {boolean} enabled
     */
    setEnabled: (enabled) => {
      if (!enabled) {
        // OFF 시 전체 초기화
        set({
          isEnabled: false,
          trails: new Map(),
          frameIndex: 0,
        });
      } else {
        set({ isEnabled: true });
      }
    },

    /**
     * 항적 전체 초기화 (정지, 슬라이더 탐색 시 호출)
     */
    clearTrails: () => {
      set({
        trails: new Map(),
        frameIndex: 0,
      });
    },

    /**
     * 프레임 기록 (매 렌더링마다 호출)
     * @param {Array<{vesselId: string, lon: number, lat: number}>} positions
     */
    recordFrame: (positions) => {
      const state = get();
      if (!state.isEnabled || positions.length === 0) return;

      const newFrameIndex = state.frameIndex + 1;
      const newTrailsMap = new Map(state.trails);
      const { maxFrames } = state;

      // 각 선박의 현재 위치를 항적에 추가
      for (const pos of positions) {
        const { vesselId, lon, lat } = pos;

        // NaN 체크
        if (isNaN(lon) || isNaN(lat)) continue;

        const vesselTrails = newTrailsMap.get(vesselId) || [];

        // 새 포인트 추가
        vesselTrails.push({
          lon,
          lat,
          frameIndex: newFrameIndex,
          vesselId,
        });

        // maxFrames 초과 시 오래된 포인트 제거
        while (vesselTrails.length > maxFrames) {
          vesselTrails.shift();
        }

        newTrailsMap.set(vesselId, vesselTrails);
      }

      // 더 이상 위치가 없는 선박의 오래된 포인트 정리
      const currentVesselIds = new Set(positions.map((p) => p.vesselId));
      newTrailsMap.forEach((trails, vesselId) => {
        if (!currentVesselIds.has(vesselId)) {
          const validTrails = trails.filter(
            (t) => newFrameIndex - t.frameIndex < maxFrames
          );
          if (validTrails.length === 0) {
            newTrailsMap.delete(vesselId);
          } else {
            newTrailsMap.set(vesselId, validTrails);
          }
        }
      });

      set({
        trails: newTrailsMap,
        frameIndex: newFrameIndex,
      });
    },

    /**
     * 모든 가시 포인트 반환 (렌더링용)
     * @returns {PlaybackTrailPoint[]}
     */
    getVisiblePoints: () => {
      const state = get();
      const result = [];

      state.trails.forEach((points) => {
        points.forEach((point) => {
          const frameAge = state.frameIndex - point.frameIndex;
          if (frameAge < state.maxFrames) {
            result.push(point);
          }
        });
      });

      return result;
    },

    /**
     * 포인트 투명도 계산 (0~1)
     * @param {number} pointFrameIndex
     * @returns {number}
     */
    getOpacity: (pointFrameIndex) => {
      const state = get();
      const frameAge = state.frameIndex - pointFrameIndex;

      if (frameAge >= state.maxFrames) return 0; // 기준 초과 → 완전 투명
      if (frameAge <= 0) return 1; // 최신 포인트 → 불투명

      // 선형 감소: 최신(frameAge=0) = 1, 가장 오래된(frameAge=maxFrames) = 0
      return 1 - frameAge / state.maxFrames;
    },

    /**
     * 포인트 크기 계산 (px)
     * @param {number} pointFrameIndex
     * @returns {number}
     */
    getPointSize: (pointFrameIndex) => {
      const state = get();
      const frameAge = state.frameIndex - pointFrameIndex;

      if (frameAge >= state.maxFrames) return state.minPointSize; // 기준 초과 → 최소 크기
      if (frameAge <= 0) return state.maxPointSize; // 최신 → 최대 크기

      // 선형 감소: 최신 = maxPointSize, 가장 오래된 = minPointSize
      const ratio = 1 - frameAge / state.maxFrames;
      return state.minPointSize + (state.maxPointSize - state.minPointSize) * ratio;
    },

    /**
     * 재생 배속 업데이트 (maxFrames 자동 재계산)
     * @param {number} speed - 재생 배속
     */
    updatePlaybackSpeed: (speed) => {
      const newMaxFrames = calculateMaxFrames(speed);
      set({
        playbackSpeed: speed,
        maxFrames: newMaxFrames,
      });
    },

    /**
     * 설정 변경
     * @param {Object} config
     */
    setConfig: (config) => {
      set({
        maxFrames: config.maxFrames ?? get().maxFrames,
        maxPointSize: config.maxPointSize ?? get().maxPointSize,
        minPointSize: config.minPointSize ?? get().minPointSize,
      });
    },
  }))
);

export default usePlaybackTrailStore;
