import React, { useState, useEffect, useCallback, useMemo, useRef } from 'react';
import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom';
import { startOfDay } from 'date-fns';
import './App.css';
import 'react-date-range/dist/styles.css';
import 'react-date-range/dist/theme/default.css';
import { formatDateValue, formatRangeLabel } from './utils/dateUtils';
import useSyncProgress from './hooks/useSyncProgress';
import useNotificationSettings from './hooks/useNotificationSettings';
import useConfigManager from './hooks/useConfigManager';
import useStoreSync from './hooks/useStoreSync';
import useDirtyNavigationGuard from './hooks/useDirtyNavigationGuard';
import useSessionManager from './hooks/useSessionManager';
import useAdminSettings from './hooks/useAdminSettings';
import useUserPreferences from './hooks/useUserPreferences';
import NavigationTabs from './components/NavigationTabs';
import LoginView from './components/LoginView';
import DashboardView from './components/DashboardView';
import AdminSettingsPanel from './components/AdminSettingsPanel';
import AdminAccessMessage from './components/AdminAccessMessage';
import DirtyNavigationDialog from './components/DirtyNavigationDialog';
import ConfirmationDialog from './components/ConfirmationDialog';
import StoreSyncOverlay from './components/StoreSyncOverlay';
import RangePickerModal from './components/RangePickerModal';
import StoreWatchPage from './components/StoreWatchPage';
import DebugPage from './components/DebugPage';
import JournalPage from './components/JournalPage';

function App() {
  const [credentials, setCredentials] = useState({ email: '', password: '' });
  const [stores, setStores] = useState([]);
  const [loading, setLoading] = useState(false);
  const [status, setStatus] = useState('');
  const [error, setError] = useState('');
  const [availableCollapsed, setAvailableCollapsed] = useState(true);
  const [initializing, setInitializing] = useState(false);
  const [activeRangePicker, setActiveRangePicker] = useState(null);
  const [confirmDialog, setConfirmDialog] = useState({ open: false, resolve: null });
  const [notificationPanelOpen, setNotificationPanelOpen] = useState(false);
  const [focusedStoreId, setFocusedStoreId] = useState(null);
  const [nearestStoreLabel, setNearestStoreLabel] = useState(null);
  const [regularPickupMap, setRegularPickupMap] = useState({});
  const [registeredPickups, setRegisteredPickups] = useState([]);
  const bootstrapOnceRef = useRef(false);
  const minSelectableDate = useMemo(() => startOfDay(new Date()), []);

  const weekdays = ['Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag', 'Sonntag'];
  const unauthorizedResetRef = useRef(() => {});
  const notifyUnauthorized = useCallback(() => {
    unauthorizedResetRef.current?.();
  }, []);

  const normalizeConfigEntries = useCallback((entries) => {
    if (!Array.isArray(entries)) {
      return [];
    }
    return entries.map((entry) => {
      if (!entry || typeof entry !== 'object') {
        return entry;
      }
      const normalized = { ...entry };
      if (normalized.desiredDate) {
        if (normalized.desiredDate) {
          normalized.desiredDateRange = {
            start: normalized.desiredDate,
            end: normalized.desiredDate
          };
        }
        delete normalized.desiredDate;
      }
      if (normalized.desiredDateRange) {
        const startValue = normalized.desiredDateRange.start || null;
        const endValue = normalized.desiredDateRange.end || null;
        const normalizedStart = startValue || endValue || null;
        const normalizedEnd = endValue || startValue || null;
        if (!normalizedStart && !normalizedEnd) {
          delete normalized.desiredDateRange;
        } else {
          normalized.desiredDateRange = {
            start: normalizedStart,
            end: normalizedEnd
          };
        }
      }
      return normalized;
    });
  }, []);
  const {
    syncProgress,
    startSyncProgress,
    updateSyncProgress,
    finishSyncProgress,
    nudgeSyncProgress
  } = useSyncProgress();

  const {
    session,
    authorizedFetch,
    bootstrapSession,
    performLogout,
    storeToken,
    getStoredToken
  } = useSessionManager({
    normalizeConfigEntries,
    onUnauthorized: notifyUnauthorized,
    setError,
    setLoading
  });

  const {
    config,
    setConfig,
    isDirty,
    setIsDirty,
    persistConfigUpdate,
    saveConfig
  } = useConfigManager({
    sessionToken: session?.token,
    authorizedFetch,
    setStatus,
    setError,
    setLoading
  });

  const {
    preferences,
    loading: preferencesLoading,
    error: preferencesError
  } = useUserPreferences({
    authorizedFetch,
    sessionToken: session?.token
  });

  const {
    fetchConfig,
    syncStoresWithProgress,
    refreshStoresAndConfig
  } = useStoreSync({
    sessionToken: session?.token,
    authorizedFetch,
    setStatus,
    setError,
    setLoading,
    setStores,
    setRegularPickupMap,
    setConfig,
    normalizeConfigEntries,
    setIsDirty,
    startSyncProgress,
    updateSyncProgress,
    finishSyncProgress
  });

  useEffect(() => {
    if (!session?.token || isDirty || initializing) {
      return undefined;
    }
    fetchConfig(session.token, { silent: true });
    const intervalId = setInterval(() => {
      fetchConfig(session.token, { silent: true });
    }, 60 * 1000);
    return () => {
      clearInterval(intervalId);
    };
  }, [fetchConfig, initializing, isDirty, session?.token]);

  useEffect(() => {
    if (!session?.token || initializing || isDirty) {
      return undefined;
    }
    let cancelled = false;
    async function refreshLastPickupInfo() {
      try {
        const response = await authorizedFetch('/api/config/last-pickup/refresh', { method: 'POST' }, session.token);
        if (!response.ok) {
          throw new Error(`HTTP ${response.status}`);
        }
        await response.json();
        if (!cancelled && !isDirty) {
          await fetchConfig(session.token, { silent: true });
        }
      } catch (error) {
        if (!cancelled) {
          console.warn('Letzte Abholung konnte nicht im Hintergrund aktualisiert werden:', error.message);
        }
      }
    }
    refreshLastPickupInfo();
    return () => {
      cancelled = true;
    };
  }, [authorizedFetch, fetchConfig, initializing, isDirty, session?.token]);

  useEffect(() => {
    let aborted = false;
    async function lookupNearestStore() {
      if (
        !authorizedFetch ||
        !preferences?.location ||
        !Number.isFinite(preferences.location.lat) ||
        !Number.isFinite(preferences.location.lon)
      ) {
        setNearestStoreLabel(null);
        return;
      }
      try {
        const params = new URLSearchParams({
          lat: String(preferences.location.lat),
          lon: String(preferences.location.lon)
        });
        const response = await authorizedFetch(`/api/location/nearest-store?${params.toString()}`);
        if (!response.ok) {
          throw new Error(`HTTP ${response.status}`);
        }
        const data = await response.json();
        if (!aborted) {
          setNearestStoreLabel(
            data.store
              ? {
                  label: data.store.label,
                  distanceKm: data.store.distanceKm
                }
              : null
          );
        }
      } catch (error) {
        if (!aborted) {
          setNearestStoreLabel(null);
          console.error('Standortsuche fehlgeschlagen:', error.message);
        }
      }
    }
    lookupNearestStore();
    return () => {
      aborted = true;
    };
  }, [authorizedFetch, preferences?.location?.lat, preferences?.location?.lon]);

  const {
    adminSettings,
    adminSettingsLoading,
    setAdminSettingsSnapshot,
    clearAdminSettings,
    handleAdminSettingChange,
    handleAdminNotificationChange,
    handleIgnoredSlotChange,
    addIgnoredSlot,
    removeIgnoredSlot,
    saveAdminSettings
  } = useAdminSettings({
    session,
    authorizedFetch,
    setStatus,
    setError
  });

  const {
    requestNavigation,
    dialogState: dirtyDialogState,
    handleDirtySave,
    handleDirtyDiscard,
    handleDirtyCancel
  } = useDirtyNavigationGuard({
    isDirty,
    saveConfig,
    onDiscard: () => setIsDirty(false)
  });

  const applyBootstrapResult = useCallback(
    (result = {}) => {
      if (!result) {
        return {};
      }
      setStores(Array.isArray(result.stores) ? result.stores : []);
      setAdminSettingsSnapshot(result.adminSettings ?? null);
      setConfig(Array.isArray(result.config) ? result.config : []);
      if (result.regularPickupMap && typeof result.regularPickupMap === 'object') {
        setRegularPickupMap(result.regularPickupMap);
      }
      return result;
    },
    [setStores, setAdminSettingsSnapshot, setConfig, setRegularPickupMap]
  );

  const resetSessionState = useCallback(() => {
    setConfig([]);
    setStores([]);
    setRegisteredPickups([]);
    setStatus('');
    setError('');
    clearAdminSettings();
    setAvailableCollapsed(true);
    setInitializing(false);
  }, [
    setConfig,
    setStores,
    setRegisteredPickups,
    setStatus,
    setError,
    clearAdminSettings,
    setAvailableCollapsed,
    setInitializing
  ]);

  useEffect(() => {
    unauthorizedResetRef.current = resetSessionState;
  }, [resetSessionState]);

  const {
    notificationSettings,
    notificationCapabilities,
    notificationDirty,
    notificationLoading,
    notificationSaving,
    notificationMessage,
    notificationError,
    copyFeedback,
    loadNotificationSettings,
    handleNotificationFieldChange,
    saveNotificationSettings,
    sendNotificationTest,
    copyToClipboard
  } = useNotificationSettings({
    authorizedFetch,
    sessionToken: session?.token
  });

  const loadRegisteredPickups = useCallback(
    async (tokenOverride) => {
      const tokenToUse = tokenOverride || session?.token;
      if (!tokenToUse) {
        setRegisteredPickups([]);
        return [];
      }
      try {
        const response = await authorizedFetch('/api/pickups/registered', {}, tokenToUse);
        if (!response.ok) {
          throw new Error(`HTTP ${response.status}`);
        }
        const data = await response.json();
        const pickups = Array.isArray(data?.pickups) ? data.pickups : [];
        setRegisteredPickups(pickups);
        return pickups;
      } catch (error) {
        console.warn('Eingetragene Foodsharing-Slots konnten nicht geladen werden:', error.message);
        setRegisteredPickups([]);
        return [];
      }
    },
    [authorizedFetch, session?.token]
  );

  useEffect(() => {
    if (!session?.token || initializing) {
      return;
    }
    loadRegisteredPickups(session.token);
  }, [initializing, loadRegisteredPickups, session?.token]);

  const handleLogin = async (event) => {
    event.preventDefault();
    setLoading(true);
    setError('');
    setStatus('');
    setInitializing(true);
    startSyncProgress('Anmeldung wird geprüft...', 5, true);
    const ticker = setInterval(() => nudgeSyncProgress('Anmeldung wird geprüft...', 2, 40), 1000);

    try {
      const response = await fetch('/api/auth/login', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(credentials)
      });

      if (!response.ok) {
        throw new Error(`HTTP ${response.status}`);
      }

      const data = await response.json();
      storeToken(data.token);
      clearInterval(ticker);
      updateSyncProgress('Zugang bestätigt. Session wird aufgebaut...', 45);
      const bootstrapResult = applyBootstrapResult(
        await bootstrapSession(data.token, { progress: { update: updateSyncProgress } })
      );
      const needsStoreSync = !bootstrapResult?.storesFresh || !!bootstrapResult?.storeRefreshJob;
      if (needsStoreSync) {
        await syncStoresWithProgress({
          reason: 'login-auto',
          startJob: !bootstrapResult?.storeRefreshJob,
          reuseOverlay: true,
          block: true,
          tokenOverride: data.token
        });
      }
      await loadRegisteredPickups(data.token);
      updateSyncProgress('Login abgeschlossen', 98);
      setStatus('Anmeldung erfolgreich. Konfiguration geladen.');
      setTimeout(() => setStatus(''), 3000);
    } catch (err) {
      setError(`Login fehlgeschlagen: ${err.message}`);
    } finally {
      clearInterval(ticker);
      finishSyncProgress();
      setInitializing(false);
      setLoading(false);
    }
  };

  const handleLogout = () => {
    requestNavigation('dich abzumelden', performLogout);
  };

  const askConfirmation = useCallback(
    (options = {}) =>
      new Promise((resolve) => {
        setConfirmDialog({
          open: true,
          title: options.title || 'Bitte bestätigen',
          message: options.message || 'Bist du sicher?',
          confirmLabel: options.confirmLabel || 'Ja',
          cancelLabel: options.cancelLabel || 'Abbrechen',
          confirmTone: options.confirmTone || 'primary',
          resolve
        });
      }),
    []
  );

  const handleConfirmDialog = useCallback((result) => {
    setConfirmDialog((prev) => {
      if (prev?.resolve) {
        prev.resolve(result);
      }
      return { open: false };
    });
  }, []);

  useEffect(() => {
    let ticker;
    let cancelled = false;
    (async () => {
      if (bootstrapOnceRef.current) {
        return;
      }
      bootstrapOnceRef.current = true;
      const storedToken = getStoredToken();
      if (!storedToken) {
        return;
      }
      setInitializing(true);
      try {
        startSyncProgress('Session wird wiederhergestellt...', 5, true);
        ticker = setInterval(() => nudgeSyncProgress('Session wird wiederhergestellt...', 1, 40), 1000);
        const result = applyBootstrapResult(
          await bootstrapSession(storedToken, { progress: { update: updateSyncProgress } })
        );
        if (ticker) {
          clearInterval(ticker);
          ticker = null;
        }
        if (!cancelled) {
          const needsStoreSync = !result?.storesFresh || !!result?.storeRefreshJob;
          if (needsStoreSync) {
            await syncStoresWithProgress({
              reason: 'session-auto',
              startJob: !result?.storeRefreshJob,
              reuseOverlay: true,
              block: true,
              tokenOverride: storedToken
            });
          }
          await loadRegisteredPickups(storedToken);
        }
        finishSyncProgress();
      } catch (err) {
        console.warn('Konnte Session nicht wiederherstellen:', err);
        finishSyncProgress();
      } finally {
        setInitializing(false);
      }
    })();
    return () => {
      cancelled = true;
      if (ticker) {
        clearInterval(ticker);
      }
    };
  }, [
    applyBootstrapResult,
    bootstrapSession,
    finishSyncProgress,
    getStoredToken,
    loadRegisteredPickups,
    nudgeSyncProgress,
    startSyncProgress,
    syncStoresWithProgress,
    updateSyncProgress
  ]);

  useEffect(() => {
    const handleBeforeUnload = (event) => {
      if (!isDirty) {
        return;
      }
      event.preventDefault();
      event.returnValue = '';
      return '';
    };
    window.addEventListener('beforeunload', handleBeforeUnload);
    return () => {
      window.removeEventListener('beforeunload', handleBeforeUnload);
    };
  }, [isDirty]);

  const deleteEntry = async (entryId) => {
    const confirmed = await askConfirmation({
      title: 'Eintrag löschen',
      message: 'Soll dieser Eintrag dauerhaft gelöscht werden?',
      confirmLabel: 'Löschen',
      confirmTone: 'danger'
    });
    if (!confirmed) {
      return;
    }
    await persistConfigUpdate(
      (prev) => prev.filter((item) => item.id !== entryId),
      'Eintrag gelöscht!',
      { autoCommit: true }
    );
  };

  const hideEntry = async (entryId) => {
    const confirmed = await askConfirmation({
      title: 'Betrieb ausblenden',
      message: 'Soll dieser Betrieb ausgeblendet werden?',
      confirmLabel: 'Ausblenden'
    });
    if (!confirmed) {
      return;
    }
    await persistConfigUpdate(
      (prev) => prev.map((item) => (item.id === entryId ? { ...item, hidden: true } : item)),
      'Betrieb ausgeblendet.',
      { autoCommit: true }
    );
  };

  const handleToggleActive = (entryId) => {
    setIsDirty(true);
    setConfig((prev) =>
      prev.map((item) =>
        item.id === entryId ? { ...item, active: !item.active } : item
      )
    );
  };

  const handleToggleAutoDeactivate = (entryId) => {
    setIsDirty(true);
    setConfig((prev) =>
      prev.map((item) =>
        item.id === entryId ? { ...item, autoDeactivate: item.autoDeactivate === false } : item
      )
    );
  };

  const handleToggleProfileCheck = (entryId) => {
    setIsDirty(true);
    setConfig((prev) =>
      prev.map((item) =>
        item.id === entryId ? { ...item, checkProfileId: !item.checkProfileId } : item
      )
    );
  };

  const handleToggleOnlyNotify = (entryId) => {
    setIsDirty(true);
    setConfig((prev) =>
      prev.map((item) =>
        item.id === entryId ? { ...item, onlyNotify: !item.onlyNotify } : item
      )
    );
  };

  const handleToggleDormantSkip = (entryId) => {
    setIsDirty(true);
    setConfig((prev) =>
      prev.map((item) =>
        item.id === entryId ? { ...item, skipDormantCheck: !item.skipDormantCheck } : item
      )
    );
  };

  const handleWeekdayChange = (entryId, value) => {
    setIsDirty(true);
    setConfig((prev) =>
      prev.map((item) => {
        if (item.id !== entryId) {
          return item;
        }
        return { ...item, desiredWeekday: value || null };
      })
    );
    if (value) {
      setActiveRangePicker((prev) => (prev === entryId ? null : prev));
    }
  };

  const handleDateRangeSelection = useCallback(
    (entryId, startDate, endDate) => {
      setIsDirty(true);
      setConfig((prev) =>
        prev.map((item) => {
          if (item.id !== entryId) {
            return item;
          }
          const updated = { ...item };
          const startValue = formatDateValue(startDate);
          const endValue = formatDateValue(endDate);
          if (startValue || endValue) {
            updated.desiredDateRange = {
              start: startValue || endValue,
              end: endValue || startValue
            };
          } else if (updated.desiredDateRange) {
            delete updated.desiredDateRange;
          }
          if (updated.desiredDate) {
            delete updated.desiredDate;
          }
          return updated;
        })
      );
    },
    [setConfig, setIsDirty]
  );

  const configMap = useMemo(() => {
    const map = new Map();
    config.forEach((item) => {
      if (item?.id) {
        map.set(String(item.id), item);
      }
    });
    return map;
  }, [config]);

  const visibleConfig = useMemo(() => config.filter((item) => !item.hidden), [config]);

  const activeRangeEntry = useMemo(() => {
    if (!activeRangePicker) {
      return null;
    }
    return config.find((item) => item.id === activeRangePicker) || null;
  }, [activeRangePicker, config]);

  useEffect(() => {
    if (!activeRangePicker) {
      return;
    }
    if (!activeRangeEntry) {
      setActiveRangePicker(null);
    }
  }, [activeRangePicker, activeRangeEntry]);

  const ntfyPreviewUrl = useMemo(() => {
    if (
      !notificationCapabilities.ntfy.enabled ||
      !notificationCapabilities.ntfy.serverUrl ||
      !notificationSettings.ntfy.topic
    ) {
      return null;
    }
    const server = notificationCapabilities.ntfy.serverUrl.replace(/\/+$/, '');
    if (!server) {
      return null;
    }
    const sanitizedTopic = notificationSettings.ntfy.topic.trim().replace(/^-+|-+$/g, '');
    if (!sanitizedTopic) {
      return null;
    }
    const prefix = (notificationCapabilities.ntfy.topicPrefix || '').replace(/^-+|-+$/g, '');
    const slug = `${prefix}${sanitizedTopic}` || sanitizedTopic || prefix;
    if (!slug) {
      return null;
    }
    return `${server}/${slug}`;
  }, [
    notificationCapabilities.ntfy.enabled,
    notificationCapabilities.ntfy.serverUrl,
    notificationCapabilities.ntfy.topicPrefix,
    notificationSettings.ntfy.topic
  ]);

  const handleStoreSelection = async (store) => {
    const storeId = String(store.id);
    const existing = configMap.get(storeId);
    if (existing && !existing.hidden) {
      setFocusedStoreId(storeId);
      return;
    }
    const confirmed = await askConfirmation({
      title: 'Betrieb hinzufügen',
      message: `Soll der Betrieb "${store.name}" zur Liste hinzugefügt werden?`,
      confirmLabel: 'Hinzufügen'
    });
    if (!confirmed) {
      return;
    }
    const message = existing ? 'Betrieb wieder eingeblendet.' : 'Betrieb zur Liste hinzugefügt.';
    await persistConfigUpdate(
      (prev) => {
        const already = prev.find((item) => item.id === storeId);
        if (already) {
          return prev.map((item) =>
            item.id === storeId
              ? {
                  ...item,
                  hidden: false,
                  label: item.label || store.name || `Store ${storeId}`
                }
              : item
          );
        }
        return [
          ...prev,
          {
            id: storeId,
            label: store.name || `Store ${storeId}`,
            active: false,
            autoDeactivate: true,
            checkProfileId: true,
            onlyNotify: false,
            skipDormantCheck: false,
            hidden: false
          }
        ];
      },
      message,
      { autoCommit: true }
    );
    setFocusedStoreId(storeId);
  };

  const userLocationWithLabel = useMemo(() => {
    if (!preferences?.location) {
      return null;
    }
    if (preferences.location.label) {
      return preferences.location;
    }
    if (nearestStoreLabel) {
      return {
        ...preferences.location,
        label: nearestStoreLabel.label,
        labelDistanceKm: nearestStoreLabel.distanceKm
      };
    }
    return { ...preferences.location };
  }, [preferences?.location, nearestStoreLabel]);

  const handleRefreshStoresAndPickups = useCallback(
    async (options) => {
      await refreshStoresAndConfig(options);
      await loadRegisteredPickups();
    },
    [loadRegisteredPickups, refreshStoresAndConfig]
  );

  const sharedNotificationProps = {
    error: notificationError,
    message: notificationMessage,
    settings: notificationSettings,
    capabilities: notificationCapabilities,
    loading: notificationLoading,
    dirty: notificationDirty,
    saving: notificationSaving,
    onReset: loadNotificationSettings,
    onSave: saveNotificationSettings,
    onFieldChange: handleNotificationFieldChange,
    onSendTest: sendNotificationTest,
    onCopyLink: copyToClipboard,
    copyFeedback,
    ntfyPreviewUrl
  };

  if (!session?.token) {
    return (
      <>
        <LoginView
          credentials={credentials}
          onCredentialsChange={setCredentials}
          error={error}
          loading={loading}
          initializing={initializing}
          onSubmit={handleLogin}
        />
        <StoreSyncOverlay state={syncProgress} />
      </>
    );
  }

  if (initializing) {
    return (
      <>
        <div className="min-h-screen flex items-center justify-center bg-gray-100">
          <div className="text-center p-8 bg-white rounded-lg shadow">
            <p className="text-xl font-semibold text-gray-800 mb-2">Initialisiere...</p>
            <p className="text-gray-500">Bitte warte, bis alle Betriebe geprüft wurden.</p>
          </div>
        </div>
        <StoreSyncOverlay state={syncProgress} />
      </>
    );
  }

  if (loading) {
    return (
      <>
        <div className="flex justify-center items-center min-h-screen bg-gray-100">
          <div className="text-center p-8">
            <div className="animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-blue-500 mx-auto mb-4"></div>
            <p className="text-xl">Lade Daten...</p>
          </div>
        </div>
        <StoreSyncOverlay state={syncProgress} />
      </>
    );
  }

  const dashboardContent = (
    <DashboardView
      session={session}
      onRefresh={handleRefreshStoresAndPickups}
      onLogout={handleLogout}
      notificationPanelOpen={notificationPanelOpen}
      onToggleNotificationPanel={() => setNotificationPanelOpen((prev) => !prev)}
      notificationProps={sharedNotificationProps}
      stores={stores}
      availableCollapsed={availableCollapsed}
      onToggleStores={() => setAvailableCollapsed((prev) => !prev)}
      onStoreSelect={handleStoreSelection}
      configMap={configMap}
      regularPickupMap={regularPickupMap}
      error={error}
      onDismissError={() => setError('')}
      status={status}
      visibleConfig={visibleConfig}
      config={config}
      registeredPickups={registeredPickups}
      onToggleActive={handleToggleActive}
      onToggleAutoDeactivate={handleToggleAutoDeactivate}
      onToggleProfileCheck={handleToggleProfileCheck}
      onToggleOnlyNotify={handleToggleOnlyNotify}
      onToggleDormantSkip={handleToggleDormantSkip}
      onWeekdayChange={handleWeekdayChange}
      weekdays={weekdays}
      onRangePickerRequest={setActiveRangePicker}
      formatRangeLabel={formatRangeLabel}
      onSaveConfig={saveConfig}
      onResetConfig={() => fetchConfig()}
      onHideEntry={hideEntry}
      onDeleteEntry={deleteEntry}
      canDelete={Boolean(session?.isAdmin)}
      isDirty={isDirty}
      focusedStoreId={focusedStoreId}
      onClearFocus={() => setFocusedStoreId(null)}
      userLocation={userLocationWithLabel}
      locationLoading={preferencesLoading}
      locationError={preferencesError}
    />
  );

  const adminPageContent = session?.isAdmin ? (
    <AdminSettingsPanel
      adminSettings={adminSettings}
      adminSettingsLoading={adminSettingsLoading}
      status={status}
      error={error}
      onDismissError={() => setError('')}
      onSettingChange={handleAdminSettingChange}
      onIgnoredSlotChange={handleIgnoredSlotChange}
      onAddIgnoredSlot={addIgnoredSlot}
      onRemoveIgnoredSlot={removeIgnoredSlot}
      onNotificationChange={handleAdminNotificationChange}
      onSave={saveAdminSettings}
    />
  ) : (
    <AdminAccessMessage />
  );

  return (
    <Router>
      <>
        <div className="min-h-screen bg-gray-100 py-6">
          <div className="max-w-6xl mx-auto px-4">
            <NavigationTabs
              isAdmin={session?.isAdmin}
              onProtectedNavigate={requestNavigation}
              profileName={session?.profile?.name}
              onLogout={handleLogout}
              onRefresh={() => handleRefreshStoresAndPickups({ block: false })}
              onToggleNotifications={() => setNotificationPanelOpen((prev) => !prev)}
              notificationPanelOpen={notificationPanelOpen}
              notificationLoading={notificationLoading}
            />
            <Routes>
              <Route path="/" element={dashboardContent} />
              <Route
                path="/store-watch"
                element={
                  session?.isAdmin ? (
                    <StoreWatchPage
                      authorizedFetch={authorizedFetch}
                      knownStores={stores}
                      userLocation={userLocationWithLabel}
                      locationLoading={preferencesLoading}
                      locationError={preferencesError}
                      notificationPanelOpen={notificationPanelOpen}
                      onToggleNotificationPanel={() => setNotificationPanelOpen((prev) => !prev)}
                      notificationProps={sharedNotificationProps}
                      isAdmin
                    />
                  ) : <Navigate to="/" replace />
                }
              />
              <Route
                path="/journal"
                element={session?.isAdmin ? <JournalPage authorizedFetch={authorizedFetch} stores={stores} /> : <Navigate to="/" replace />}
              />
              <Route
                path="/debug"
                element={
                  session?.isAdmin ? <DebugPage authorizedFetch={authorizedFetch} /> : <AdminAccessMessage />
                }
              />
              <Route path="/admin" element={adminPageContent} />
              <Route path="*" element={<Navigate to="/" replace />} />
            </Routes>
          </div>
        </div>
        <StoreSyncOverlay state={syncProgress} />
        <DirtyNavigationDialog
          open={dirtyDialogState.open}
          message={dirtyDialogState.message}
          onSave={handleDirtySave}
          onDiscard={handleDirtyDiscard}
          onCancel={handleDirtyCancel}
          saving={dirtyDialogState.saving}
        />
        <ConfirmationDialog
          open={!!confirmDialog.open}
          title={confirmDialog.title}
          message={confirmDialog.message}
          confirmLabel={confirmDialog.confirmLabel}
          cancelLabel={confirmDialog.cancelLabel}
          confirmTone={confirmDialog.confirmTone}
          onConfirm={() => handleConfirmDialog(true)}
          onCancel={() => handleConfirmDialog(false)}
        />
        <RangePickerModal
          entry={activeRangeEntry}
          minDate={minSelectableDate}
          config={config}
          registeredPickups={registeredPickups}
          onSelectRange={(startDate, endDate) =>
            activeRangeEntry ? handleDateRangeSelection(activeRangeEntry.id, startDate, endDate) : null
          }
          onResetRange={() => {
            if (activeRangeEntry) {
              handleDateRangeSelection(activeRangeEntry.id, null, null);
            }
            setActiveRangePicker(null);
          }}
          onClose={() => setActiveRangePicker(null)}
        />
      </>
    </Router>
  );
}

export default App;
