import React, { useState, useCallback, useEffect } from 'react';
import { FlyerDisplay } from './components/FlyerDisplay';
import { ExtractedDataTable } from './components/ExtractedDataTable';
import { AnalysisPanel } from './components/AnalysisPanel';
import { PriceChart } from './components/PriceChart';
import { ErrorDisplay } from './components/ErrorDisplay';
import { Header } from './components/Header';
import { isImageAFlyer, extractCoreDataFromImage, extractAddressFromImage, extractLogoFromImage } from './services/geminiService';
import type { FlyerItem, Flyer, MasterGroceryItem, DealItem, ProcessingStage, StageStatus, Store, Profile, ShoppingList, ShoppingListItem } from './types';
import { BulkImporter } from './components/BulkImporter';
import { PriceHistoryChart } from './components/PriceHistoryChart';
import { supabase, uploadFlyerImage, createFlyerRecord, saveFlyerItems, getFlyers, getFlyerItems, initializeSupabase, findFlyerByChecksum, getWatchedItems, addWatchedItem, getAllMasterItems, getFlyerItemsForFlyers, countFlyerItemsForFlyers, getUserProfile, updateUserPreferences, removeWatchedItem, getShoppingLists, createShoppingList, addShoppingListItem, updateShoppingListItem, removeShoppingListItem, deleteShoppingList, uploadLogoAndUpdateStore } from './services/supabaseClient';
import { FlyerList } from './components/FlyerList';
import { recordProcessingTime, getAverageProcessingTime } from './utils/processingTimer';
import { ProcessingStatus } from './components/ProcessingStatus';
import { SupabaseConnector } from './components/SupabaseConnector';
import { generateFileChecksum } from './utils/checksum';
import { convertPdfToImageFiles } from './utils/pdfConverter';
import { BulkImportSummary } from './components/BulkImportSummary';
import { WatchedItemsList } from './components/WatchedItemsList';
import { withTimeout } from './utils/timeout';
import { Session } from '@supabase/supabase-js';
import { ProfileManager } from './components/ProfileManager';
import { ShoppingListComponent } from './components/ShoppingList';
import { SystemCheck } from './components/SystemCheck';
import { LoginPage } from './components/LoginPage';
import { VoiceAssistant } from './components/VoiceAssistant';

function App() {
  const [isAuthenticated, setIsAuthenticated] = useState(false);
  const [isFakeAuth, setIsFakeAuth] = useState(false);
  const [loginError, setLoginError] = useState<string | null>(null);

  const [flyers, setFlyers] = useState<Flyer[]>([]);
  const [selectedFlyer, setSelectedFlyer] = useState<Flyer | null>(null);
  const [flyerItems, setFlyerItems] = useState<FlyerItem[]>([]);
  const [watchedItems, setWatchedItems] = useState<MasterGroceryItem[]>([]);
  const [masterItems, setMasterItems] = useState<MasterGroceryItem[]>([]);
  const [activeDeals, setActiveDeals] = useState<DealItem[]>([]);
  const [activeDealsLoading, setActiveDealsLoading] = useState(false);
  const [totalActiveItems, setTotalActiveItems] = useState(0);

  const [isProcessing, setIsProcessing] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const [processingProgress, setProcessingProgress] = useState(0);
  const [currentFile, setCurrentFile] = useState<string | null>(null);
  const [fileCount, setFileCount] = useState<{current: number, total: number} | null>(null);
  const [importSummary, setImportSummary] = useState<{
    processed: string[];
    skipped: string[];
    errors: { fileName: string; message: string }[];
  } | null>(null);

  const [isDbConnected, setIsDbConnected] = useState(!!supabase);
  const [isReady, setIsReady] = useState(false);
  const [isDarkMode, setIsDarkMode] = useState(false);
  const [unitSystem, setUnitSystem] = useState<'metric' | 'imperial'>('imperial');
  const [session, setSession] = useState<Session | null>(null);
  const [profile, setProfile] = useState<Profile | null>(null);
  const [isProfileManagerOpen, setIsProfileManagerOpen] = useState(false);
  const [isVoiceAssistantOpen, setIsVoiceAssistantOpen] = useState(false);

  const [processingStages, setProcessingStages] = useState<ProcessingStage[]>([]);
  const [estimatedTime, setEstimatedTime] = useState(0);
  const [pageProgress, setPageProgress] = useState<{current: number, total: number} | null>(null);
  
  const [shoppingLists, setShoppingLists] = useState<ShoppingList[]>([]);
  const [activeListId, setActiveListId] = useState<number | null>(null);

  // Effect to set initial theme based on user profile, local storage, or system preference
  useEffect(() => {
    if (profile && profile.preferences?.darkMode !== undefined) {
        // Preference from DB
        const dbDarkMode = profile.preferences.darkMode;
        setIsDarkMode(dbDarkMode);
        document.documentElement.classList.toggle('dark', dbDarkMode);
    } else {
        // Fallback to local storage or system preference
        const savedMode = localStorage.getItem('darkMode');
        const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
        const initialDarkMode = savedMode !== null ? savedMode === 'true' : prefersDark;
        setIsDarkMode(initialDarkMode);
        document.documentElement.classList.toggle('dark', initialDarkMode);
    }
  }, [profile]);

  // Effect to set initial unit system based on user profile or local storage
  useEffect(() => {
    if (profile && profile.preferences?.unitSystem) {
        setUnitSystem(profile.preferences.unitSystem);
    } else {
        const savedSystem = localStorage.getItem('unitSystem') as 'metric' | 'imperial' | null;
        if (savedSystem) {
            setUnitSystem(savedSystem);
        }
    }
  }, [profile]);


  const toggleDarkMode = async () => {
    const newMode = !isDarkMode;
    setIsDarkMode(newMode);
    document.documentElement.classList.toggle('dark', newMode);
    
    if (session && !isFakeAuth) {
      const newPreferences = { ...profile?.preferences, darkMode: newMode };
      setProfile(p => p ? {...p, preferences: newPreferences} : null);
      await updateUserPreferences(session.user.id, newPreferences);
    } else {
      localStorage.setItem('darkMode', String(newMode));
    }
  };

  const toggleUnitSystem = async () => {
    const newSystem = unitSystem === 'metric' ? 'imperial' : 'metric';
    setUnitSystem(newSystem);

    if (session && !isFakeAuth) {
        // FIX: Explicitly type `newPreferences` to prevent TypeScript from incorrectly widening `newSystem` to a generic `string`.
        // This ensures compatibility with the `Profile` type definition.
        const newPreferences: Profile['preferences'] = { ...profile?.preferences, unitSystem: newSystem };
        setProfile(p => p ? {...p, preferences: newPreferences} : null);
        await updateUserPreferences(session.user.id, newPreferences);
    } else {
        localStorage.setItem('unitSystem', newSystem);
    }
  };


  const fetchFlyers = useCallback(async () => {
    if (!supabase) return;
    try {
      const allFlyers = await getFlyers();
      setFlyers(allFlyers);
    } catch(e: any) {
      setError(e.message);
    }
  }, []);

  const fetchWatchedItems = useCallback(async (userId: string | undefined) => {
    if (!supabase || !userId) {
        setWatchedItems([]);
        return;
    }
    try {
        const items = await getWatchedItems(userId);
        setWatchedItems(items);
    } catch (e: any) {
        setError(`Could not fetch watched items: ${e.message}`);
    }
  }, []);

  const fetchShoppingLists = useCallback(async (userId: string | undefined) => {
    if (!supabase || !userId) {
        setShoppingLists([]);
        setActiveListId(null);
        return;
    }
    try {
        const lists = await getShoppingLists(userId);
        setShoppingLists(lists);
        if (lists.length > 0 && !activeListId) {
            setActiveListId(lists[0].id);
        } else if (lists.length === 0) {
            setActiveListId(null);
        }
    } catch (e: any) {
        setError(`Could not fetch shopping lists: ${e.message}`);
    }
  }, [activeListId]);
  
  const fetchMasterItems = useCallback(async () => {
    if (!supabase) return;
    try {
        const items = await getAllMasterItems();
        setMasterItems(items);
    } catch (e: any) {
        setError(`Could not fetch master item list: ${e.message}`);
    }
  }, []);

  useEffect(() => {
    if (!supabase) {
      const storedUrl = localStorage.getItem('supabaseUrl');
      const storedKey = localStorage.getItem('supabaseAnonKey');
      if (storedUrl && storedKey) {
        initializeSupabase(storedUrl, storedKey);
        setIsDbConnected(true);
      }
    } else {
        setIsDbConnected(true);
    }
  }, []);

  // Effect to handle authentication state changes.
  useEffect(() => {
    if (!isDbConnected || !supabase) return;

    // If using fake auth, set up a mock session and state.
    // We don't listen to Supabase auth changes in this mode.
    if (isFakeAuth) {
        const mockSession = {
            user: { id: 'test-user-123', email: 'test@test.com' },
        } as unknown as Session;
        setSession(mockSession);
        setProfile({ id: 'test-user-123' });
        // User-specific data is empty for the fake user.
        setWatchedItems([]);
        setShoppingLists([]);
        return; // Early return to avoid setting up the real auth listener.
    }

    // This logic ONLY runs for real Supabase authentication.
    const fetchRealUserSessionData = async (session: Session | null) => {
        setSession(session);
        if (session) {
            const userProfile = await getUserProfile(session.user.id);
            setProfile(userProfile);
            fetchWatchedItems(session.user.id);
            fetchShoppingLists(session.user.id);
        } else {
            setProfile(null);
            setWatchedItems([]);
            setShoppingLists([]);
        }
    };

    supabase.auth.getSession().then(({ data: { session } }) => {
        fetchRealUserSessionData(session);
    });

    const { data: { subscription } } = supabase.auth.onAuthStateChange((_event, session) => {
        if (_event === "SIGNED_OUT") {
            setIsProfileManagerOpen(false);
            // On sign out, always de-authenticate, regardless of fake auth status.
            setIsAuthenticated(false);
            setIsFakeAuth(false);
        }
        fetchRealUserSessionData(session);
    });

    return () => subscription.unsubscribe();
  }, [isDbConnected, fetchWatchedItems, fetchShoppingLists, isFakeAuth]);


  useEffect(() => {
    if (isDbConnected && isReady) {
        fetchFlyers();
        fetchMasterItems();
    }
  }, [isDbConnected, isReady, fetchFlyers, fetchMasterItems]);


  const resetState = useCallback(() => {
    setSelectedFlyer(null);
    setFlyerItems([]);
    setError(null);
    setProcessingProgress(0);
    setProcessingStages([]);
    setImportSummary(null);
    setCurrentFile(null);
    setPageProgress(null);
    setFileCount(null);
  }, []);

  const handleFlyerSelect = useCallback(async (flyer: Flyer) => {
    setSelectedFlyer(flyer);
    setError(null);
    setFlyerItems([]); // Clear previous items

    if (!supabase) return;
    
    try {
        const items = await getFlyerItems(flyer.id);
        setFlyerItems(items);
    } catch (e: any) {
        setError(e.message);
    }
  }, []);

  useEffect(() => {
    if (!isProcessing && !selectedFlyer && flyers.length > 0) {
      handleFlyerSelect(flyers[0]);
    }
  }, [flyers, selectedFlyer, handleFlyerSelect, isProcessing]);

  useEffect(() => {
    const findActiveDeals = async () => {
      if (!isDbConnected || !isReady || flyers.length === 0 || watchedItems.length === 0) {
        setActiveDeals([]);
        return;
      }
      
      setActiveDealsLoading(true);

      try {
        const today = new Date();
        today.setHours(0, 0, 0, 0);

        const validFlyers = flyers.filter(flyer => {
            if (!flyer.valid_from || !flyer.valid_to) return false;
            try {
                const from = new Date(`${flyer.valid_from}T00:00:00`);
                const to = new Date(`${flyer.valid_to}T00:00:00`);
                return today >= from && today <= to;
            } catch (e) {
                console.error("Error parsing flyer date", e);
                return false;
            }
        });

        if (validFlyers.length === 0) {
          setActiveDeals([]);
          return;
        }

        const validFlyerIds = validFlyers.map(f => f.id);
        const allItems = await getFlyerItemsForFlyers(validFlyerIds);

        const watchedItemIds = new Set(watchedItems.map(item => item.id));
        const dealItemsRaw = allItems.filter(item =>
            item.master_item_id && watchedItemIds.has(item.master_item_id)
        );

        const flyerIdToStoreName = new Map(validFlyers.map(f => [f.id, f.store?.name || 'Unknown Store']));
        
        const deals: DealItem[] = dealItemsRaw.map(item => ({
            item: item.item,
            price_display: item.price_display,
            price_in_cents: item.price_in_cents,
            quantity: item.quantity,
            storeName: flyerIdToStoreName.get(item.flyer_id!) || 'Unknown Store',
            master_item_name: item.master_item_name,
            unit_price: item.unit_price,
        }));

        setActiveDeals(deals);
      } catch (e: any) {
          setError(`Could not fetch active deals: ${e.message}`);
      } finally {
        setActiveDealsLoading(false);
      }
    };

    findActiveDeals();
  }, [flyers, watchedItems, isDbConnected, isReady]);

  useEffect(() => {
    const calculateTotalActiveItems = async () => {
        if (!isDbConnected || !isReady || flyers.length === 0) {
            setTotalActiveItems(0);
            return;
        }

        try {
            const today = new Date();
            today.setHours(0, 0, 0, 0);

            const validFlyers = flyers.filter(flyer => {
                if (!flyer.valid_from || !flyer.valid_to) return false;
                try {
                    const from = new Date(`${flyer.valid_from}T00:00:00`);
                    const to = new Date(`${flyer.valid_to}T00:00:00`);
                    return today >= from && today <= to;
                } catch (e) {
                    console.error("Error parsing flyer date", e);
                    return false;
                }
            });

            if (validFlyers.length === 0) {
                setTotalActiveItems(0);
                return;
            }

            const validFlyerIds = validFlyers.map(f => f.id);
            const totalCount = await countFlyerItemsForFlyers(validFlyerIds);
            setTotalActiveItems(totalCount);
        } catch (e: any) {
            console.error("Failed to calculate total active items:", e.message);
            setTotalActiveItems(0);
        }
    };

    calculateTotalActiveItems();
  }, [flyers, isDbConnected, isReady]);

  const processFiles = async (files: File[], checksum: string, originalFileName: string, updateStage?: (index: number, updates: Partial<ProcessingStage>) => void) => {
    let stageIndex = 0;
    
    // Stage: Validating Flyer
    updateStage?.(stageIndex, { status: 'in-progress' });
    const isFlyer = await withTimeout(isImageAFlyer(files[0]), 15000);
    if (!isFlyer) {
      throw new Error("The uploaded image does not appear to be a grocery flyer.");
    }
    updateStage?.(stageIndex++, { status: 'completed' }); // stageIndex is now 1
  
    const pageCount = files.length;
    const coreDataTimeout = 60000 * pageCount;
    const nonCriticalTimeout = 30000;

    // Granular stages for core data extraction
    const storeInfoStageIndex = stageIndex;       // Stage 1: Extracting Store Name & Sale Dates
    const itemExtractionStageIndex = stageIndex + 1; // Stage 2: Extracting All Items from Flyer

    // Mark both stages as in-progress for the single AI call
    updateStage?.(storeInfoStageIndex, { status: 'in-progress' });
    updateStage?.(itemExtractionStageIndex, { status: 'in-progress', detail: pageCount > 1 ? `(${pageCount} pages)` : undefined });
    
    let progressInterval: number | undefined;
    let extractedData;

    try {
      if (pageCount > 1) {
        let currentPage = 0;
        const intervalTime = 2500;
        // Attach progress bar to the item extraction stage
        progressInterval = window.setInterval(() => {
          currentPage++;
          if (currentPage <= pageCount) {
            updateStage?.(itemExtractionStageIndex, { progress: { current: currentPage, total: pageCount } });
          } else {
            clearInterval(progressInterval);
          }
        }, intervalTime);
      }

      extractedData = await withTimeout(extractCoreDataFromImage(files, masterItems), coreDataTimeout);
      
      // Mark both stages as completed after the AI call finishes
      updateStage?.(storeInfoStageIndex, { status: 'completed' });
      updateStage?.(itemExtractionStageIndex, { status: 'completed', progress: null });
    } finally {
      if (progressInterval) {
        clearInterval(progressInterval);
      }
    }
    
    const { store_name, valid_from, valid_to, items: extractedItems } = extractedData;
    stageIndex += 2; // Increment by 2 for the stages we just completed. stageIndex is now 3

    // Stage: Extracting Store Address
    let storeAddress: string | null = null;
    try {
        updateStage?.(stageIndex, { status: 'in-progress' });
        storeAddress = await withTimeout(extractAddressFromImage(files[0]), nonCriticalTimeout);
        updateStage?.(stageIndex++, { status: 'completed' }); // stageIndex is now 4
    } catch (e: any) {
        console.warn("Non-critical step failed: Address extraction.", e.message);
        updateStage?.(stageIndex++, { status: 'error', detail: '(Skipped)' }); // stageIndex is now 4
    }

    // Stage: Extracting Store Logo
    let storeLogoBase64: string | null = null;
    try {
        updateStage?.(stageIndex, { status: 'in-progress' });
        const logoData = await withTimeout(extractLogoFromImage(files.slice(0, 1)), nonCriticalTimeout);
        storeLogoBase64 = logoData.store_logo_base_64;
        updateStage?.(stageIndex++, { status: 'completed' }); // stageIndex is now 5
    } catch (e: any) {
        console.warn("Non-critical step failed: Logo extraction.", e.message);
        updateStage?.(stageIndex++, { status: 'error', detail: '(Skipped)' }); // stageIndex is now 5
    }
    
    if (!supabase) {
        throw new Error("Cannot process flyer: Supabase client not initialized.");
    }
  
    // Stage: Uploading Flyer Image
    updateStage?.(stageIndex, { status: 'in-progress' });
    const imageUrl = await withTimeout(uploadFlyerImage(files[0]), 30000);
    updateStage?.(stageIndex++, { status: 'completed' }); // stageIndex is now 6
  
    // Stage: Creating Database Record
    updateStage?.(stageIndex, { status: 'in-progress' });
    const newFlyer = await withTimeout(createFlyerRecord(originalFileName, imageUrl, checksum, store_name, valid_from, valid_to, storeAddress), 10000);
    if (!newFlyer) {
      throw new Error("Could not create a record for the new flyer.");
    }

    // Upload logo if extracted and if the store doesn't have one already.
    // This is a non-critical, fire-and-forget task.
    if (storeLogoBase64 && newFlyer.store_id && !newFlyer.store?.logo_url) {
        uploadLogoAndUpdateStore(newFlyer.store_id, storeLogoBase64);
    }

    updateStage?.(stageIndex++, { status: 'completed' }); // stageIndex is now 7
    
    // Stage: Saving Items to Database
    updateStage?.(stageIndex, { status: 'in-progress' });
    const savedItems = await withTimeout(saveFlyerItems(extractedItems, newFlyer.id), 20000);
    updateStage?.(stageIndex, { status: 'completed' });
  
    return { newFlyer, items: savedItems };
  };

  const setupProcessingStages = (isPdf: boolean) => {
    const pendingStatus: StageStatus = 'pending';
    const isDbAvailable = !!supabase;

    const baseStages: ProcessingStage[] = [
        ...(isDbAvailable ? [{ name: 'Checking for Duplicates', status: pendingStatus, critical: true }] : []),
        { name: 'Validating Flyer', status: pendingStatus, critical: true },
        { name: 'Extracting Store Name & Sale Dates', status: pendingStatus, critical: true },
        { name: 'Extracting All Items from Flyer', status: pendingStatus, critical: true },
        { name: 'Extracting Store Address', status: pendingStatus, critical: false },
        { name: 'Extracting Store Logo', status: pendingStatus, critical: false },
        ...(isDbAvailable ? [
            { name: 'Uploading Flyer Image', status: pendingStatus, critical: true },
            { name: 'Creating Database Record', status: pendingStatus, critical: true },
            { name: 'Saving Items to Database', status: pendingStatus, critical: true },
        ] : []),
    ];
    if (isPdf) {
      return [
        { name: 'Analyzing PDF', status: pendingStatus, critical: true },
        { name: 'Converting PDF to Images', status: pendingStatus, critical: true },
        ...baseStages
      ];
    }
    return baseStages;
  };

  const handleProcessFiles = useCallback(async (files: FileList) => {
    if (files.length === 0) return;
    
    resetState();
    setIsProcessing(true);
    setProcessingProgress(0);
    setError(null);

    if (!supabase) {
      setError("A database connection is required to process flyers.");
      setIsProcessing(false);
      return;
    }

    const summary = {
      processed: [] as string[],
      skipped: [] as string[],
      errors: [] as { fileName: string; message: string }[],
    };
    
    const avgTime = getAverageProcessingTime();
    setEstimatedTime(avgTime * files.length);

    for (let i = 0; i < files.length; i++) {
        const originalFile = files[i];
        setCurrentFile(originalFile.name);
        setFileCount({ current: i + 1, total: files.length });
        setPageProgress(null);
        
        const isPdf = originalFile.type === 'application/pdf';
        setProcessingStages(setupProcessingStages(isPdf));

        const updateStage = (index: number, updates: Partial<ProcessingStage>) => {
          setProcessingStages(prev =>
              prev.map((stage, j) => (j === index ? { ...stage, ...updates } : stage))
          );
        };
        
        let currentStageIndex = 0;
        const startTime = Date.now();

        try {
            let filesToProcess: File[];
            let checksum = '';

            if (isPdf) {
              updateStage(currentStageIndex, { status: 'in-progress' });
              const onPdfProgress = (currentPage: number, totalPages: number) => {
                  setPageProgress({ current: currentPage, total: totalPages });
              };
              const { imageFiles, pageCount } = await convertPdfToImageFiles(originalFile, onPdfProgress);
              filesToProcess = imageFiles;
              setPageProgress(null);
              updateStage(currentStageIndex++, { status: 'completed', detail: `(${pageCount} pages)` });
              updateStage(currentStageIndex++, { status: 'completed' });
            } else {
              filesToProcess = [originalFile];
            }

            if (supabase) {
              updateStage(currentStageIndex, { status: 'in-progress' });
              checksum = await generateFileChecksum(originalFile);
              const existing = await findFlyerByChecksum(checksum);
              if (existing) {
                  console.log(`Skipping duplicate file: ${originalFile.name}`);
                  summary.skipped.push(originalFile.name);
                  updateStage(currentStageIndex, { status: 'completed', detail: '(Duplicate)' });
                  setProcessingProgress(((i + 1) / files.length) * 100);
                  continue;
              }
              updateStage(currentStageIndex++, { status: 'completed' });
            }
            
            const processFilesUpdateStage = (idx: number, updates: Partial<ProcessingStage>) => updateStage(idx + currentStageIndex, updates);

            await processFiles(filesToProcess, checksum, originalFile.name, processFilesUpdateStage);
            summary.processed.push(originalFile.name);
        } catch (e: any) {
            console.error(`Failed to process ${originalFile.name}:`, e);
            summary.errors.push({ fileName: originalFile.name, message: e.message });
            setProcessingStages(prev => prev.map(stage => {
                if (stage.status === 'in-progress' && (stage.critical ?? true)) {
                    return {...stage, status: 'error'};
                }
                return stage;
            }));
            await new Promise(resolve => setTimeout(resolve, 2000));
        } finally {
            const duration = (Date.now() - startTime) / 1000;
            recordProcessingTime(duration);
        }
        setProcessingProgress(((i + 1) / files.length) * 100);
    }
    
    await fetchFlyers();
    await fetchMasterItems();
    setImportSummary(summary);
    setIsProcessing(false);
    setCurrentFile(null);
    setPageProgress(null);
    setFileCount(null);
  }, [resetState, fetchFlyers, masterItems, fetchMasterItems]);

  const handleAddWatchedItem = useCallback(async (itemName: string, category: string) => {
    if (!supabase || !session || isFakeAuth) return;
    try {
        const updatedOrNewItem = await addWatchedItem(session.user.id, itemName, category);
        setWatchedItems(prevItems => {
            const itemExists = prevItems.some(item => item.id === updatedOrNewItem.id);
            if (!itemExists) {
                const newItems = [...prevItems, updatedOrNewItem];
                return newItems.sort((a,b) => a.name.localeCompare(b.name));
            }
            return prevItems; // Item already existed in list
        });
    } catch (e: any) {
        setError(`Could not add watched item: ${e.message}`);
        await fetchWatchedItems(session?.user?.id);
    }
  }, [session, fetchWatchedItems, isFakeAuth]);
  
  const handleRemoveWatchedItem = useCallback(async (masterItemId: number) => {
    if (!supabase || !session || isFakeAuth) return;
    try {
      await removeWatchedItem(session.user.id, masterItemId);
      setWatchedItems(prevItems => prevItems.filter(item => item.id !== masterItemId));
    } catch (e: any) {
      setError(`Could not remove watched item: ${e.message}`);
    }
  }, [session, isFakeAuth]);

  // --- Shopping List Handlers ---
  const handleCreateList = useCallback(async (name: string) => {
    if (!session || isFakeAuth) return;
    try {
      const newList = await createShoppingList(session.user.id, name);
      setShoppingLists(prev => [...prev, newList]);
      setActiveListId(newList.id);
    } catch (e: any) {
      setError(`Could not create list: ${e.message}`);
    }
  }, [session, isFakeAuth]);

  const handleDeleteList = useCallback(async (listId: number) => {
    if (!session || isFakeAuth) return;
    try {
      await deleteShoppingList(listId);
      const newLists = shoppingLists.filter(l => l.id !== listId);
      setShoppingLists(newLists);
      if (activeListId === listId) {
        setActiveListId(newLists.length > 0 ? newLists[0].id : null);
      }
    } catch (e: any) {
      setError(`Could not delete list: ${e.message}`);
    }
  }, [session, shoppingLists, activeListId, isFakeAuth]);

  const handleAddShoppingListItem = useCallback(async (listId: number, item: { masterItemId?: number, customItemName?: string }) => {
    if (!session || isFakeAuth) return;
    try {
        const newItem = await addShoppingListItem(listId, item);
        setShoppingLists(prevLists => prevLists.map(list => {
            if (list.id === listId) {
                // Avoid adding duplicates to the state if it's already there
                const itemExists = list.items.some(i => i.id === newItem.id);
                if (itemExists) return list;
                return { ...list, items: [...list.items, newItem] };
            }
            return list;
        }));
    } catch (e: any) {
        setError(`Could not add item to list: ${e.message}`);
    }
  }, [session, isFakeAuth]);

  const handleUpdateShoppingListItem = useCallback(async (itemId: number, updates: Partial<ShoppingListItem>) => {
    if (!session || !activeListId || isFakeAuth) return;
    try {
        const updatedItem = await updateShoppingListItem(itemId, updates);
        setShoppingLists(prevLists => prevLists.map(list => {
            if (list.id === activeListId) {
                return { ...list, items: list.items.map(i => i.id === itemId ? updatedItem : i) };
            }
            return list;
        }));
    } catch (e: any) {
        setError(`Could not update list item: ${e.message}`);
    }
  }, [session, activeListId, isFakeAuth]);

  const handleRemoveShoppingListItem = useCallback(async (itemId: number) => {
    if (!session || !activeListId || isFakeAuth) return;
    try {
        await removeShoppingListItem(itemId);
        setShoppingLists(prevLists => prevLists.map(list => {
            if (list.id === activeListId) {
                return { ...list, items: list.items.filter(i => i.id !== itemId) };
            }
            return list;
        }));
    } catch (e: any) {
        setError(`Could not remove list item: ${e.message}`);
    }
  }, [session, activeListId, isFakeAuth]);

  const handleFakeLogin = (email: string, pass: string) => {
    if (email === 'test@test.com' && pass === 'pass123') {
        setIsAuthenticated(true);
        setIsFakeAuth(true); // Mark that we are using fake auth
        setLoginError(null);
    } else {
        setLoginError('Invalid credentials');
    }
  };

  const handleSignOut = () => {
    if (supabase && !isFakeAuth) {
        supabase.auth.signOut();
    }
    // For fake auth, signing out just resets local state.
    // The onAuthStateChange listener will handle real sign-outs.
    setIsAuthenticated(false);
    setIsFakeAuth(false);
    setSession(null);
  };


  const hasData = flyerItems.length > 0;

  if (!isAuthenticated) {
    return <LoginPage onLogin={handleFakeLogin} error={loginError} />;
  }

  return (
    <div className="bg-gray-100 dark:bg-gray-950 min-h-screen font-sans text-gray-800 dark:text-gray-200">
      <Header 
        isDarkMode={isDarkMode} 
        toggleDarkMode={toggleDarkMode}
        unitSystem={unitSystem}
        toggleUnitSystem={toggleUnitSystem}
        session={session}
        onOpenProfile={() => setIsProfileManagerOpen(true)}
        onOpenVoiceAssistant={() => setIsVoiceAssistantOpen(true)}
        onSignOut={handleSignOut}
      />
      {session && profile && !isFakeAuth && (
        <ProfileManager
            isOpen={isProfileManagerOpen}
            onClose={() => setIsProfileManagerOpen(false)}
            session={session}
            profile={profile}
            onProfileUpdate={(updatedProfile) => setProfile(updatedProfile)}
        />
      )}
      {session && (
          <VoiceAssistant 
              isOpen={isVoiceAssistantOpen}
              onClose={() => setIsVoiceAssistantOpen(false)}
          />
      )}
      <main className="max-w-screen-2xl mx-auto py-4 px-2.5 sm:py-6 lg:py-8">
        <div className="grid grid-cols-1 lg:grid-cols-4 gap-8 items-start">
          
          <div className="lg:col-span-1 flex flex-col space-y-6">
            {isDbConnected ? (
                <>
                    <FlyerList flyers={flyers} onFlyerSelect={handleFlyerSelect} selectedFlyerId={selectedFlyer?.id || null} />
                    {isReady && (
                        <BulkImporter 
                            onProcess={handleProcessFiles}
                            isProcessing={isProcessing}
                        />
                    )}
                    <SystemCheck onReady={() => setIsReady(true)} />
                </>
            ) : (
                <SupabaseConnector onSuccess={() => setIsDbConnected(true)} />
            )}
          </div>

          <div className="lg:col-span-2 flex flex-col space-y-6">
            <ErrorDisplay message={error} />
            
            {isProcessing ? (
              <ProcessingStatus 
                stages={processingStages} 
                estimatedTime={estimatedTime} 
                currentFile={currentFile}
                pageProgress={pageProgress}
                bulkProgress={processingProgress}
                bulkFileCount={fileCount}
              />
            ) : selectedFlyer ? (
              <>
                <FlyerDisplay
                  imageUrl={selectedFlyer.image_url}
                  store={selectedFlyer.store}
                  validFrom={selectedFlyer.valid_from}
                  validTo={selectedFlyer.valid_to}
                  storeAddress={selectedFlyer.store_address}
                />
                {hasData && (
                  <>
                    <ExtractedDataTable 
                      items={flyerItems} 
                      totalActiveItems={totalActiveItems}
                      watchedItems={watchedItems}
                      masterItems={masterItems}
                      unitSystem={unitSystem}
                      session={session}
                      onAddItem={handleAddWatchedItem}
                      shoppingLists={shoppingLists}
                      activeListId={activeListId}
                      onAddItemToList={(masterItemId) => handleAddShoppingListItem(activeListId!, { masterItemId })}
                    />
                    <AnalysisPanel flyerItems={flyerItems} store={selectedFlyer.store} />
                  </>
                )}
              </>
            ) : importSummary ? (
              <BulkImportSummary summary={importSummary} onDismiss={() => setImportSummary(null)} />
            ) : (
              <div className="text-center p-8 bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700 h-full flex flex-col justify-center min-h-[400px]">
                <h2 className="text-xl font-semibold text-gray-700 dark:text-gray-200">Welcome to Flyer Crawler!</h2>
                <p className="mt-2 text-gray-500 dark:text-gray-400">Upload a new grocery flyer to begin, or select a previously processed flyer from the list on the left.</p>
              </div>
            )}
          </div>
          
          <div className="lg:col-span-1 flex-col space-y-6">
            {isDbConnected && (
                <>
                    <ShoppingListComponent 
                        session={session}
                        lists={shoppingLists}
                        activeListId={activeListId}
                        onSelectList={setActiveListId}
                        onCreateList={handleCreateList}
                        onDeleteList={handleDeleteList}
                        onAddItem={(item) => handleAddShoppingListItem(activeListId!, item)}
                        onUpdateItem={handleUpdateShoppingListItem}
                        onRemoveItem={handleRemoveShoppingListItem}
                    />
                    <WatchedItemsList 
                        items={watchedItems}
                        onAddItem={handleAddWatchedItem}
                        onRemoveItem={handleRemoveWatchedItem}
                        session={session}
                        activeListId={activeListId}
                        onAddItemToList={(masterItemId) => handleAddShoppingListItem(activeListId!, { masterItemId })}
                    />
                    <PriceChart 
                        deals={activeDeals} 
                        isLoading={activeDealsLoading}
                        unitSystem={unitSystem}
                        session={session}
                    />
                    <PriceHistoryChart watchedItems={watchedItems} />
                </>
            )}
          </div>
        </div>
      </main>
    </div>
  );
}

export default App;