import { create } from 'zustand';
import { getTracksTimeRange } from '../lib/adapters';
import type { MultiTrackQueryContext, ProcessedTrack, TrackQueryContext } from '../model/track.types';
import { queryMultiTrack, queryTrackByDateRange } from '../services/trackQueryService';
import { useTrackPlaybackStore } from './trackPlaybackStore';

export type TrackQueryStatus = 'idle' | 'loading' | 'ready' | 'error';

interface TrackQueryState {
  tracks: ProcessedTrack[];
  disabledVesselIds: Set<string>;
  highlightedVesselId: string | null;
  isLoading: boolean;
  error: string | null;
  queryState: TrackQueryStatus;
  renderEpoch: number;
  lastQueryKey: string | null;
  queryContext: TrackQueryContext | null;
  multiQueryContext: MultiTrackQueryContext | null;
  showPoints: boolean;
  showVirtualShip: boolean;
  showLabels: boolean;
  showTrail: boolean;
  hideLiveShips: boolean;

  beginQuery: (queryKey: string, context?: TrackQueryContext) => void;
  beginMultiQuery: (queryKey: string, ctx: MultiTrackQueryContext) => Promise<void>;
  applyTracksSuccess: (tracks: ProcessedTrack[], queryKey?: string | null) => void;
  applyQueryError: (error: string, queryKey?: string | null) => void;
  closeQuery: () => void;
  requery: (startTimeIso: string, endTimeIso: string) => Promise<void>;

  setTracks: (tracks: ProcessedTrack[]) => void;
  clearTracks: () => void;
  setLoading: (loading: boolean) => void;
  setError: (error: string | null) => void;
  setHighlightedVesselId: (vesselId: string | null) => void;
  setShowPoints: (show: boolean) => void;
  setShowVirtualShip: (show: boolean) => void;
  setShowLabels: (show: boolean) => void;
  setShowTrail: (show: boolean) => void;
  setHideLiveShips: (hide: boolean) => void;
  toggleVesselEnabled: (vesselId: string) => void;
  getEnabledTracks: () => ProcessedTrack[];
  reset: () => void;
}

export const useTrackQueryStore = create<TrackQueryState>()((set, get) => ({
  tracks: [],
  disabledVesselIds: new Set<string>(),
  highlightedVesselId: null,
  isLoading: false,
  error: null,
  queryState: 'idle',
  renderEpoch: 0,
  lastQueryKey: null,
  queryContext: null,
  multiQueryContext: null,
  showPoints: true,
  showVirtualShip: true,
  showLabels: true,
  showTrail: true,
  hideLiveShips: false,

  beginQuery: (queryKey: string, context?: TrackQueryContext) => {
    useTrackPlaybackStore.getState().reset();
    set((state) => ({
      tracks: [],
      disabledVesselIds: new Set<string>(),
      highlightedVesselId: null,
      isLoading: true,
      error: null,
      queryState: 'loading',
      renderEpoch: state.renderEpoch + 1,
      lastQueryKey: queryKey,
      hideLiveShips: true,
      queryContext: context ?? state.queryContext,
      multiQueryContext: null,
    }));
  },

  beginMultiQuery: async (queryKey: string, ctx: MultiTrackQueryContext) => {
    useTrackPlaybackStore.getState().reset();
    set((state) => ({
      tracks: [],
      disabledVesselIds: new Set<string>(),
      highlightedVesselId: null,
      isLoading: true,
      error: null,
      queryState: 'loading',
      renderEpoch: state.renderEpoch + 1,
      lastQueryKey: queryKey,
      hideLiveShips: true,
      queryContext: null,
      multiQueryContext: ctx,
    }));

    try {
      const mmsis = ctx.vessels.map((v) => v.mmsi);
      const hasPermitted = ctx.vessels.some((v) => v.isPermitted);
      const tracks = await queryMultiTrack({
        mmsis,
        startTimeIso: ctx.startTimeIso,
        endTimeIso: ctx.endTimeIso,
        hasPermitted,
      });

      if (tracks.length > 0) {
        get().applyTracksSuccess(tracks, queryKey);
      } else {
        get().applyQueryError('항적 데이터가 없습니다.', queryKey);
      }
    } catch (e) {
      get().applyQueryError(e instanceof Error ? e.message : '항적 조회에 실패했습니다.', queryKey);
    }
  },

  applyTracksSuccess: (tracks: ProcessedTrack[], queryKey?: string | null) => {
    const currentQueryKey = get().lastQueryKey;
    if (queryKey != null && queryKey !== currentQueryKey) {
      return;
    }

    const range = getTracksTimeRange(tracks);
    const playback = useTrackPlaybackStore.getState();

    if (range) {
      playback.setTimeRange(range.start, range.end);
      playback.syncToRangeStart();
      playback.setPlaybackSpeed(100);
    } else {
      playback.reset();
    }

    set((state) => ({
      tracks,
      disabledVesselIds: new Set<string>(),
      highlightedVesselId: null,
      isLoading: false,
      error: null,
      queryState: 'ready',
      renderEpoch: state.renderEpoch + 1,
      lastQueryKey: queryKey ?? state.lastQueryKey,
    }));

    if (range) {
      if (typeof window !== 'undefined') {
        window.requestAnimationFrame(() => {
          useTrackPlaybackStore.getState().play();
        });
      } else {
        useTrackPlaybackStore.getState().play();
      }
    }
  },

  applyQueryError: (error: string, queryKey?: string | null) => {
    const currentQueryKey = get().lastQueryKey;
    if (queryKey != null && queryKey !== currentQueryKey) {
      return;
    }

    useTrackPlaybackStore.getState().reset();
    set((state) => ({
      tracks: [],
      disabledVesselIds: new Set<string>(),
      highlightedVesselId: null,
      isLoading: false,
      error,
      queryState: 'error',
      renderEpoch: state.renderEpoch + 1,
      lastQueryKey: queryKey ?? state.lastQueryKey,
      hideLiveShips: false,
    }));
  },

  closeQuery: () => {
    useTrackPlaybackStore.getState().reset();
    set((state) => ({
      tracks: [],
      disabledVesselIds: new Set<string>(),
      highlightedVesselId: null,
      isLoading: false,
      error: null,
      queryState: 'idle',
      renderEpoch: state.renderEpoch + 1,
      lastQueryKey: null,
      queryContext: null,
      multiQueryContext: null,
      hideLiveShips: false,
    }));
  },

  requery: async (startTimeIso: string, endTimeIso: string) => {
    const multiCtx = get().multiQueryContext;
    if (multiCtx) {
      const queryKey = `requery-multi:${Date.now()}`;
      const updatedCtx: MultiTrackQueryContext = { ...multiCtx, startTimeIso, endTimeIso };
      // Preserve multiQueryContext across beginMultiQuery
      await get().beginMultiQuery(queryKey, updatedCtx);
      return;
    }

    const ctx = get().queryContext;
    if (!ctx) return;

    const queryKey = `requery:${ctx.mmsi}:${Date.now()}`;
    const updatedContext: TrackQueryContext = { ...ctx, startTimeIso, endTimeIso };

    get().beginQuery(queryKey, updatedContext);

    try {
      const tracks = await queryTrackByDateRange({
        mmsi: updatedContext.mmsi,
        startTimeIso: updatedContext.startTimeIso,
        endTimeIso: updatedContext.endTimeIso,
        shipNameHint: updatedContext.shipNameHint,
        shipKindCodeHint: updatedContext.shipKindCodeHint,
        nationalCodeHint: updatedContext.nationalCodeHint,
        isPermitted: updatedContext.isPermitted,
      });

      if (tracks.length > 0) {
        get().applyTracksSuccess(tracks, queryKey);
      } else {
        get().applyQueryError('항적 데이터가 없습니다.', queryKey);
      }
    } catch (e) {
      get().applyQueryError(e instanceof Error ? e.message : '항적 조회에 실패했습니다.', queryKey);
    }
  },

  setTracks: (tracks: ProcessedTrack[]) => {
    get().applyTracksSuccess(tracks, get().lastQueryKey);
  },

  clearTracks: () => {
    get().closeQuery();
  },

  setLoading: (loading: boolean) =>
    set((state) => ({
      isLoading: loading,
      queryState: loading ? 'loading' : state.error ? 'error' : state.tracks.length > 0 ? 'ready' : 'idle',
    })),

  setError: (error: string | null) =>
    set((state) => ({
      error,
      queryState: error ? 'error' : state.isLoading ? 'loading' : state.tracks.length > 0 ? 'ready' : 'idle',
    })),

  setHighlightedVesselId: (vesselId: string | null) => set({ highlightedVesselId: vesselId }),
  setShowPoints: (show: boolean) => set({ showPoints: show }),
  setShowVirtualShip: (show: boolean) => set({ showVirtualShip: show }),
  setShowLabels: (show: boolean) => set({ showLabels: show }),
  setShowTrail: (show: boolean) => set({ showTrail: show }),
  setHideLiveShips: (hide: boolean) => set({ hideLiveShips: hide }),

  toggleVesselEnabled: (vesselId: string) => {
    const next = new Set(get().disabledVesselIds);
    if (next.has(vesselId)) next.delete(vesselId);
    else next.add(vesselId);
    set((state) => ({
      disabledVesselIds: next,
      renderEpoch: state.renderEpoch + 1,
    }));
  },

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

  reset: () => {
    useTrackPlaybackStore.getState().reset();
    set((state) => ({
      tracks: [],
      disabledVesselIds: new Set<string>(),
      highlightedVesselId: null,
      isLoading: false,
      error: null,
      queryState: 'idle',
      renderEpoch: state.renderEpoch + 1,
      lastQueryKey: null,
      queryContext: null,
      multiQueryContext: null,
      showPoints: true,
      showVirtualShip: true,
      showLabels: true,
      showTrail: true,
      hideLiveShips: false,
    }));
  },
}));
