/**
 * @ai-summary Data synchronization layer integrating React Query with Zustand stores
 */

import { QueryClient } from '@tanstack/react-query';
import { useNavigationStore } from '../store/navigation';
import { useUserStore } from '../store/user';
import { Vehicle } from '../../features/vehicles/types/vehicles.types';
import { apiClient } from '../api/client';

interface SyncConfig {
  enableCrossTabs: boolean;
  enableOptimisticUpdates: boolean;
  enableBackgroundSync: boolean;
  syncInterval: number;
  isAuthenticated?: () => boolean;
}

export class DataSyncManager {
  private queryClient: QueryClient;
  private config: SyncConfig;
  private syncInterval?: NodeJS.Timeout;
  private isOnline: boolean = navigator.onLine;

  constructor(queryClient: QueryClient, config: Partial<SyncConfig> = {}) {
    this.queryClient = queryClient;
    this.config = {
      enableCrossTabs: true,
      enableOptimisticUpdates: true,
      enableBackgroundSync: true,
      syncInterval: 30000, // 30 seconds
      ...config,
    };

    this.initializeSync();
  }

  private initializeSync() {
    // Listen to online/offline events
    window.addEventListener('online', this.handleOnline.bind(this));
    window.addEventListener('offline', this.handleOffline.bind(this));

    // Cross-tab synchronization
    if (this.config.enableCrossTabs) {
      this.initializeCrossTabSync();
    }

    // Background sync
    if (this.config.enableBackgroundSync) {
      this.startBackgroundSync();
    }
  }

  private handleOnline() {
    this.isOnline = true;
    useUserStore.getState().setOnlineStatus(true);

    // Trigger cache revalidation when coming back online
    this.queryClient.invalidateQueries();
    console.log('DataSync: Back online, revalidating cache');
  }

  private handleOffline() {
    this.isOnline = false;
    useUserStore.getState().setOnlineStatus(false);
    console.log('DataSync: Offline mode enabled');
  }

  private initializeCrossTabSync() {
    // Listen for storage changes from other tabs
    window.addEventListener('storage', (event) => {
      if (event.key?.startsWith('motovaultpro-')) {
        // Another tab updated store data
        if (event.key.includes('user-context')) {
          // User data changed in another tab - sync React Query cache
          this.syncUserDataFromStorage();
        } else if (event.key.includes('mobile-navigation')) {
          // Navigation state changed - could affect cache keys
          this.syncNavigationFromStorage();
        }
      }
    });
  }

  private async syncUserDataFromStorage() {
    try {
      const userData = useUserStore.getState().userProfile;
      if (userData) {
        // Update query cache with latest user data
        this.queryClient.setQueryData(['user', userData.id], userData);
        console.log('DataSync: User data synchronized from another tab');
      }
    } catch (error) {
      console.warn('DataSync: Failed to sync user data from storage:', error);
    }
  }

  private async syncNavigationFromStorage() {
    try {
      const navigationState = useNavigationStore.getState();

      // If the selected vehicle changed in another tab, preload its data
      if (navigationState.selectedVehicleId) {
        await this.queryClient.prefetchQuery({
          queryKey: ['vehicles', navigationState.selectedVehicleId],
          queryFn: () => this.fetchVehicleById(navigationState.selectedVehicleId!),
        });
        console.log('DataSync: Vehicle data preloaded from navigation sync');
      }
    } catch (error) {
      console.warn('DataSync: Failed to sync navigation from storage:', error);
    }
  }

  private startBackgroundSync() {
    this.syncInterval = setInterval(() => {
      if (this.isOnline) {
        const state = useNavigationStore.getState();
        console.log('[DataSync] Tick', {
          at: new Date().toISOString(),
          activeScreen: state.activeScreen,
          selectedVehicleId: state.selectedVehicleId,
        });
        this.performBackgroundSync();
      }
    }, this.config.syncInterval);
  }

  private async performBackgroundSync() {
    // Guard: only sync if user is authenticated
    if (this.config.isAuthenticated && !this.config.isAuthenticated()) {
      return;
    }

    try {
      // Update last sync timestamp
      useUserStore.getState().updateLastSync();

      // Strategically refresh critical data
      const navigationState = useNavigationStore.getState();

      // If on vehicles screen, refresh vehicles data
      if (navigationState.activeScreen === 'Vehicles') {
        console.log('[DataSync] Invalidating query', { key: ['vehicles'], reason: 'background-sync:vehicles-screen' });
        await this.queryClient.invalidateQueries({ queryKey: ['vehicles'] });
      }

      // If viewing specific vehicle details, refresh that vehicle's data
      if (
        navigationState.activeScreen === 'Vehicles' &&
        navigationState.vehicleSubScreen === 'detail' &&
        navigationState.selectedVehicleId
      ) {
        const key = ['vehicles', navigationState.selectedVehicleId];
        console.log('[DataSync] Invalidating query', { key, reason: 'background-sync:selected-vehicle:vehicles-detail' });
        await this.queryClient.invalidateQueries({ queryKey: key });
      }

      console.log('DataSync: Background sync completed');
    } catch (error) {
      console.warn('DataSync: Background sync failed:', error);
    }
  }

  // Helper method to fetch vehicle by ID (would normally import from vehicles API)
  private async fetchVehicleById(id: string): Promise<Vehicle | null> {
    try {
      const response = await apiClient.get(`/vehicles/${id}`);
      return response.data;
    } catch (error) {
      console.warn(`Failed to fetch vehicle ${id}:`, error);
      return null;
    }
  }


  // Public methods for optimistic updates
  public async optimisticVehicleUpdate(vehicleId: string, updates: Partial<Vehicle>) {
    if (!this.config.enableOptimisticUpdates) return;

    try {
      // Optimistically update query cache
      this.queryClient.setQueryData(['vehicles', vehicleId], (old: Vehicle | undefined) => {
        if (!old) return old;
        return { ...old, ...updates };
      });

      // Also update the vehicles list cache
      this.queryClient.setQueryData(['vehicles'], (old: Vehicle[] | undefined) => {
        if (!old) return old;
        return old.map(vehicle =>
          vehicle.id === vehicleId ? { ...vehicle, ...updates } : vehicle
        );
      });

      console.log('DataSync: Optimistic vehicle update applied');
    } catch (error) {
      console.warn('DataSync: Optimistic update failed:', error);
    }
  }

  public async prefetchForNavigation(targetScreen: string) {
    // Guard: only prefetch if user is authenticated
    if (this.config.isAuthenticated && !this.config.isAuthenticated()) {
      console.log('DataSync: Skipping prefetch - user not authenticated');
      return;
    }

    try {
      switch (targetScreen) {
        case 'Vehicles':
          // Prefetch vehicles list if not already cached
          await this.queryClient.prefetchQuery({
            queryKey: ['vehicles'],
            queryFn: () => this.fetchVehicles(),
            staleTime: 1000 * 60 * 5, // 5 minutes
          });
          break;

        case 'Log Fuel':
          // Prefetch vehicles for fuel logging dropdown
          await this.queryClient.prefetchQuery({
            queryKey: ['vehicles'],
            queryFn: () => this.fetchVehicles(),
          });
          break;

        default:
          // No specific prefetching needed
          break;
      }
    } catch (error) {
      console.warn('DataSync: Prefetch failed for', targetScreen, error);
    }
  }

  private async fetchVehicles(): Promise<Vehicle[]> {
    try {
      const response = await apiClient.get('/vehicles');
      return response.data;
    } catch (error) {
      console.warn('Failed to fetch vehicles:', error);
      return [];
    }
  }

  public cleanup() {
    if (this.syncInterval) {
      clearInterval(this.syncInterval);
    }

    window.removeEventListener('online', this.handleOnline);
    window.removeEventListener('offline', this.handleOffline);
  }
}
