import { useEffect, useRef, useState } from 'react';
import {
  addScannedCardToCollection,
  addScannedCardToDeck,
  addScannedCardToOwned,
  createScannerCollection,
  fetchScannerCollections,
  fetchScannerDecks,
  routeScannedCardToDestination,
} from './scanner-route-api.js';
import { destinationActionKey, mergeScannedCardEntry } from './scanner-session.js';

/**
 * Scanned-card queue, bulk selection, in-flight guards, and destination lists.
 */
export function useScannerQueue({ user, sessionDestination, scanDefaults }) {
  const [scannedCards, setScannedCards] = useState([]);
  const [collections, setCollections] = useState([]);
  const [decks, setDecks] = useState([]);
  const [selectedCards, setSelectedCards] = useState(new Set());
  const [bulkAction, setBulkAction] = useState('');
  const [bulkTarget, setBulkTarget] = useState('');
  const [isProcessing, setIsProcessing] = useState(false);
  const [autoRouteError, setAutoRouteError] = useState(null);
  const [showCreateCollection, setShowCreateCollection] = useState(false);
  const [newCollectionName, setNewCollectionName] = useState('');

  const addingInFlightRef = useRef(new Set());
  const [addingCardIds, setAddingCardIds] = useState(() => new Set());

  useEffect(() => {
    if (!user) return;

    let cancelled = false;

    (async () => {
      try {
        const [loadedCollections, loadedDecks] = await Promise.all([
          fetchScannerCollections(),
          fetchScannerDecks(),
        ]);
        if (cancelled) return;
        setCollections(loadedCollections);
        setDecks(loadedDecks);
      } catch (error) {
        console.error('Error loading scanner destinations:', error);
      }
    })();

    return () => {
      cancelled = true;
    };
  }, [user]);

  const syncAddingState = () => {
    setAddingCardIds(new Set(addingInFlightRef.current));
  };

  const tryBeginAdding = (cardId) => {
    if (addingInFlightRef.current.has(cardId)) return false;
    addingInFlightRef.current.add(cardId);
    syncAddingState();
    return true;
  };

  const endAdding = (cardId) => {
    addingInFlightRef.current.delete(cardId);
    syncAddingState();
  };

  const markCardAsProcessed = (cardId, action) => {
    setScannedCards((prev) =>
      prev.map((card) =>
        card.id === cardId ? { ...card, processed: true, processedAction: action } : card
      )
    );
  };

  const handleCardScanned = async (cardData) => {
    setAutoRouteError(null);

    const { cardEntry, scannedCards: nextQueue } = mergeScannedCardEntry(
      scannedCards,
      cardData,
      scanDefaults
    );
    setScannedCards(nextQueue);

    if (!sessionDestination) return;

    if (!cardEntry.databaseId) {
      setAutoRouteError(
        `"${cardEntry.name}" was queued but is not in the catalog yet — add it manually after review.`
      );
      return;
    }

    try {
      if (!tryBeginAdding(cardEntry.id)) return;
      await routeScannedCardToDestination(cardEntry, sessionDestination);
      markCardAsProcessed(cardEntry.id, destinationActionKey(sessionDestination));
    } catch (error) {
      console.error('Auto-route failed:', error);
      setAutoRouteError(
        `Could not add "${cardEntry.name}" to ${sessionDestination.label}. Use the card actions below.`
      );
    } finally {
      endAdding(cardEntry.id);
    }
  };

  const incrementCardQuantity = (cardId) => {
    setScannedCards((prev) =>
      prev.map((card) =>
        card.id === cardId ? { ...card, quantity: (card.quantity || 1) + 1 } : card
      )
    );
  };

  const decrementCardQuantity = (cardId) => {
    setScannedCards((prev) =>
      prev.map((card) =>
        card.id === cardId
          ? { ...card, quantity: Math.max(1, (card.quantity || 1) - 1) }
          : card
      )
    );
  };

  const updateCardMetadata = (cardId, patch) => {
    setScannedCards((prev) =>
      prev.map((card) => (card.id === cardId ? { ...card, ...patch } : card))
    );
  };

  const addSingleCardToOwned = async (card) => {
    if (!tryBeginAdding(card.id)) return;
    try {
      await addScannedCardToOwned(card);
      markCardAsProcessed(card.id, 'owned');
    } catch (error) {
      console.error('Error adding card to owned:', error);
    } finally {
      endAdding(card.id);
    }
  };

  const addSingleCardToCollection = async (card, collectionId) => {
    if (!tryBeginAdding(card.id)) return;
    try {
      await addScannedCardToCollection(card, collectionId);
      markCardAsProcessed(card.id, 'collection');
    } catch (error) {
      console.error('Error adding card to collection:', error);
    } finally {
      endAdding(card.id);
    }
  };

  const addSingleCardToDeck = async (card, deckId) => {
    if (!tryBeginAdding(card.id)) return;
    try {
      await addScannedCardToDeck(card, deckId);
      markCardAsProcessed(card.id, 'deck');
    } catch (error) {
      console.error('Error adding card to deck:', error);
    } finally {
      endAdding(card.id);
    }
  };

  const handleBulkAction = async (actionOverride, targetOverride) => {
    const action = actionOverride ?? bulkAction;
    const target = targetOverride ?? bulkTarget;
    if (!action || selectedCards.size === 0) return;

    setIsProcessing(true);
    try {
      const cardsToProcess = scannedCards.filter((card) => selectedCards.has(card.id));

      for (const card of cardsToProcess) {
        if (action === 'owned') {
          if (!tryBeginAdding(card.id)) continue;
          try {
            await addScannedCardToOwned(card);
          } finally {
            endAdding(card.id);
          }
        } else if (action === 'collection' && target) {
          if (!tryBeginAdding(card.id)) continue;
          try {
            await addScannedCardToCollection(card, target);
          } finally {
            endAdding(card.id);
          }
        } else if (action === 'deck' && target) {
          if (!tryBeginAdding(card.id)) continue;
          try {
            await addScannedCardToDeck(card, target);
          } finally {
            endAdding(card.id);
          }
        } else {
          continue;
        }
        markCardAsProcessed(card.id, action);
      }

      setSelectedCards(new Set());
      setBulkAction('');
      setBulkTarget('');
    } catch (error) {
      console.error('Error processing bulk action:', error);
    } finally {
      setIsProcessing(false);
    }
  };

  const createCollection = async () => {
    if (!newCollectionName.trim()) return;

    try {
      const newCollection = await createScannerCollection(newCollectionName.trim());
      setCollections((prev) => [newCollection, ...prev]);
      setBulkTarget(newCollection.id.toString());
      setNewCollectionName('');
      setShowCreateCollection(false);
    } catch (error) {
      console.error('Error creating collection:', error);
    }
  };

  const clearScannedCards = () => {
    setScannedCards([]);
    setSelectedCards(new Set());
  };

  const removeScannedCard = (cardId) => {
    setScannedCards((prev) => prev.filter((card) => card.id !== cardId));
    setSelectedCards((prev) => {
      const next = new Set(prev);
      next.delete(cardId);
      return next;
    });
  };

  const toggleCardSelection = (cardId) => {
    setSelectedCards((prev) => {
      const next = new Set(prev);
      if (next.has(cardId)) {
        next.delete(cardId);
      } else {
        next.add(cardId);
      }
      return next;
    });
  };

  const clearSelection = () => {
    setSelectedCards(new Set());
  };

  return {
    scannedCards,
    collections,
    decks,
    selectedCards,
    isProcessing,
    addingCardIds,
    autoRouteError,
    showCreateCollection,
    setShowCreateCollection,
    newCollectionName,
    setNewCollectionName,
    handleCardScanned,
    incrementCardQuantity,
    decrementCardQuantity,
    updateCardMetadata,
    addSingleCardToOwned,
    addSingleCardToCollection,
    addSingleCardToDeck,
    handleBulkAction,
    createCollection,
    clearScannedCards,
    removeScannedCard,
    toggleCardSelection,
    clearSelection,
  };
}
