import { useState, useEffect, useRef, useCallback } from 'react';
import {
  addScannedCardToOwned,
  addScannedCardToCollection,
  addScannedCardToDeck,
} from './scanner-route-api.js';

const OFFLINE_QUEUE_KEY = 'deckhearth:offline-scan-queue';
const MAX_RETRIES = 3;

function loadQueue() {
  if (typeof window === 'undefined') return [];
  try {
    return JSON.parse(localStorage.getItem(OFFLINE_QUEUE_KEY)) || [];
  } catch {
    return [];
  }
}

function persistQueue(queue) {
  if (typeof window === 'undefined') return;
  localStorage.setItem(OFFLINE_QUEUE_KEY, JSON.stringify(queue));
}

async function executeAction(action, payload) {
  switch (action) {
    case 'addToOwned':
      return addScannedCardToOwned(payload);
    case 'addToCollection':
      return addScannedCardToCollection(payload, payload.collectionId);
    case 'addToDeck':
      return addScannedCardToDeck(payload, payload.deckId);
    default:
      throw new Error(`Unknown offline action: ${action}`);
  }
}

export function useScannerOffline() {
  const [isOnline, setIsOnline] = useState(
    () => typeof navigator !== 'undefined' ? navigator.onLine : true
  );
  const [queuedActions, setQueuedActions] = useState(loadQueue);
  const processingRef = useRef(false);

  const updateQueue = useCallback((updater) => {
    setQueuedActions((prev) => {
      const next = typeof updater === 'function' ? updater(prev) : updater;
      persistQueue(next);
      return next;
    });
  }, []);

  const processQueue = useCallback(async () => {
    if (processingRef.current) return;
    processingRef.current = true;

    try {
      const current = loadQueue();
      const pending = current.filter((item) => item.status === 'pending');

      for (const item of pending) {
        try {
          await executeAction(item.action, item.payload);
          updateQueue((prev) => prev.filter((q) => q.id !== item.id));
        } catch {
          updateQueue((prev) =>
            prev.map((q) => {
              if (q.id !== item.id) return q;
              const retries = q.retries + 1;
              return {
                ...q,
                retries,
                status: retries >= MAX_RETRIES ? 'failed' : 'pending',
              };
            })
          );
        }
      }
    } finally {
      processingRef.current = false;
    }
  }, [updateQueue]);

  useEffect(() => {
    const goOnline = () => {
      setIsOnline(true);
      processQueue();
    };
    const goOffline = () => setIsOnline(false);

    window.addEventListener('online', goOnline);
    window.addEventListener('offline', goOffline);
    return () => {
      window.removeEventListener('online', goOnline);
      window.removeEventListener('offline', goOffline);
    };
  }, [processQueue]);

  // Process any items left over from a previous session on mount
  useEffect(() => {
    if (isOnline && loadQueue().some((q) => q.status === 'pending')) {
      processQueue();
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  const enqueue = useCallback(
    async (action, payload) => {
      const item = {
        id: Date.now() + Math.random(),
        action,
        payload,
        timestamp: Date.now(),
        retries: 0,
        status: 'pending',
      };

      if (isOnline) {
        try {
          await executeAction(action, payload);
          return;
        } catch {
          // Network error while supposedly online — fall through to queue
        }
      }

      updateQueue((prev) => [...prev, item]);
    },
    [isOnline, updateQueue]
  );

  const pendingCount = queuedActions.filter((q) => q.status === 'pending').length;

  return { isOnline, queuedActions, enqueue, processQueue, pendingCount };
}
