import { create } from 'zustand';
import { api } from '@/lib/api';
import type { TrackPointPayload, TrackPointEvent } from '@/types/tracking';

interface TrackingState {
  trackingSessionId: string | null;
  isTracking: boolean;
  pendingPoints: TrackPointPayload[];

  startTracking(canvassSessionId?: string, lat?: number, lng?: number): Promise<void>;
  stopTracking(): Promise<void>;
  addPoint(point: TrackPointPayload): void;
  flushPoints(): Promise<void>;
  linkCanvassSession(canvassSessionId: string): Promise<void>;
  addEventPoint(lat: number, lng: number, eventType: TrackPointEvent): void;
  restoreSession(): Promise<void>;
  reset(): void;
}

export const useTrackingStore = create<TrackingState>((set, get) => ({
  trackingSessionId: null,
  isTracking: false,
  pendingPoints: [],

  startTracking: async (canvassSessionId, lat, lng) => {
    if (get().isTracking) return;
    try {
      const { data } = await api.post('/map/tracking/sessions', {
        canvassSessionId,
        latitude: lat,
        longitude: lng,
      });
      set({ trackingSessionId: data.id, isTracking: true });
    } catch {
      // Non-critical — tracking just won't record
    }
  },

  stopTracking: async () => {
    const { trackingSessionId, pendingPoints } = get();
    if (!trackingSessionId) {
      set({ isTracking: false });
      return;
    }

    // Flush remaining points before ending
    if (pendingPoints.length > 0) {
      try {
        await api.post(`/map/tracking/sessions/${trackingSessionId}/points`, {
          points: pendingPoints,
        });
      } catch {
        // Best effort
      }
    }

    try {
      await api.post(`/map/tracking/sessions/${trackingSessionId}/end`);
    } catch {
      // Best effort
    }

    set({ trackingSessionId: null, isTracking: false, pendingPoints: [] });
  },

  addPoint: (point) => {
    set((state) => ({
      pendingPoints: [...state.pendingPoints, point],
    }));
  },

  flushPoints: async () => {
    const { trackingSessionId, pendingPoints } = get();
    if (!trackingSessionId || pendingPoints.length === 0) return;

    // Take a snapshot and clear the buffer optimistically
    const toSend = [...pendingPoints];
    set({ pendingPoints: [] });

    try {
      await api.post(`/map/tracking/sessions/${trackingSessionId}/points`, {
        points: toSend,
      });
    } catch {
      // Re-add failed points to the buffer
      set((state) => ({
        pendingPoints: [...toSend, ...state.pendingPoints],
      }));
    }
  },

  linkCanvassSession: async (canvassSessionId) => {
    const { trackingSessionId } = get();
    if (!trackingSessionId) return;
    try {
      await api.post(`/map/tracking/sessions/${trackingSessionId}/link-canvass`, {
        canvassSessionId,
      });
    } catch {
      // Non-critical
    }
  },

  addEventPoint: (lat, lng, eventType) => {
    get().addPoint({
      latitude: lat,
      longitude: lng,
      recordedAt: new Date().toISOString(),
      eventType,
    });
  },

  restoreSession: async () => {
    try {
      const { data } = await api.get('/map/tracking/my/session');
      if (data) {
        set({ trackingSessionId: data.id, isTracking: true });
      }
    } catch {
      // No active session
    }
  },

  reset: () => {
    set({
      trackingSessionId: null,
      isTracking: false,
      pendingPoints: [],
    });
  },
}));
