import { Middleware } from '@reduxjs/toolkit';
import { RootState } from '../store';
import { removePendingAction, incrementRetryCount, setSyncInProgress, updateLastSyncTime } from '../slices/offlineSlice';
import { setOnlineStatus } from '../slices/networkSlice';

/**
 * Sync middleware - processes pending actions when coming back online
 */
export const syncMiddleware: Middleware<{}, RootState> = (store) => (next) => (action: any) => {
  // Check if we just came back online
  if (action.type === 'network/setOnlineStatus' && action.payload === true) {
    const state = store.getState();
    const pendingActions = state.offline?.pendingActions || [];

    if (pendingActions.length > 0) {
      console.log(`[Sync] Processing ${pendingActions.length} pending actions`);
      store.dispatch(setSyncInProgress(true));

      // Process pending actions sequentially
      processPendingActions(store, pendingActions);
    }
  }

  return next(action);
};

/**
 * Process pending actions with retry logic
 */
async function processPendingActions(store: any, pendingActions: any[]) {
  const MAX_RETRIES = 5;

  for (const pendingAction of pendingActions) {
    try {
      console.log(`[Sync] Processing action: ${pendingAction.type}`, pendingAction);

      // Reconstruct the action
      const action = {
        type: pendingAction.type,
        payload: pendingAction.payload,
      };

      // Dispatch the action (which will make the API call)
      await store.dispatch(action);

      // If successful, remove from queue
      store.dispatch(removePendingAction(pendingAction.id));
      console.log(`[Sync] Successfully synced action: ${pendingAction.type}`);
    } catch (error) {
      console.error(`[Sync] Failed to sync action: ${pendingAction.type}`, error);

      // Increment retry count
      store.dispatch(incrementRetryCount(pendingAction.id));

      // If max retries reached, remove from queue
      if (pendingAction.retryCount >= MAX_RETRIES) {
        console.error(`[Sync] Max retries reached for action: ${pendingAction.type}`);
        store.dispatch(removePendingAction(pendingAction.id));
      }
    }
  }

  // Mark sync as complete
  store.dispatch(setSyncInProgress(false));
  store.dispatch(updateLastSyncTime());
  console.log('[Sync] Sync complete');
}

/**
 * Conflict resolution strategies
 */
export enum ConflictStrategy {
  SERVER_WINS = 'server_wins',
  CLIENT_WINS = 'client_wins',
  LAST_WRITE_WINS = 'last_write_wins',
  MERGE = 'merge',
}

/**
 * Resolve conflicts between local and server data
 */
export function resolveConflict<T extends { _version?: number; updatedAt?: string }>(
  localData: T,
  serverData: T,
  strategy: ConflictStrategy = ConflictStrategy.LAST_WRITE_WINS
): T {
  switch (strategy) {
    case ConflictStrategy.SERVER_WINS:
      return serverData;

    case ConflictStrategy.CLIENT_WINS:
      return localData;

    case ConflictStrategy.LAST_WRITE_WINS:
      // Compare timestamps
      const localTime = localData.updatedAt ? new Date(localData.updatedAt).getTime() : 0;
      const serverTime = serverData.updatedAt ? new Date(serverData.updatedAt).getTime() : 0;
      return serverTime > localTime ? serverData : localData;

    case ConflictStrategy.MERGE:
      // Simple merge strategy - prefer server for system fields, local for user fields
      return {
        ...serverData,
        ...localData,
        // System fields from server
        id: serverData.id,
        createdAt: serverData.createdAt,
        updatedAt: serverData.updatedAt,
        // Metadata
        _version: Math.max(localData._version || 0, serverData._version || 0) + 1,
      };

    default:
      return serverData;
  }
}

/**
 * Version-based conflict detection
 */
export function hasConflict<T extends { _version?: number }>(
  localData: T,
  serverData: T
): boolean {
  if (!localData._version || !serverData._version) {
    return false;
  }
  return localData._version !== serverData._version;
}
