import { useCallback, useEffect, useMemo, useState } from 'react';
import {
  createColumnHelper,
  flexRender,
  getCoreRowModel,
  getFilteredRowModel,
  getSortedRowModel,
  useReactTable
} from '@tanstack/react-table';
import { haversineDistanceKm } from '../utils/distance';
import { inferLocationLabel } from '../utils/locationLabel';
import NotificationPanel from './NotificationPanel';

const REGION_STORAGE_KEY = 'storeWatchRegionSelection';
const WATCH_TABLE_STATE_KEY = 'storeWatchTableState';
const PANEL_STORAGE_KEY = 'storeWatchPanels';
const PANEL_IDS = ['stores', 'watch'];

function createDefaultPanelState() {
  return {
    order: [...PANEL_IDS],
    collapsed: PANEL_IDS.reduce(
      (acc, panelId) => ({
        ...acc,
        [panelId]: false
      }),
      {}
    )
  };
}

function formatWatchStatusLabel(status) {
  if (status === 1) {
    return 'Suchend';
  }
  if (status === 0) {
    return 'Nicht suchend';
  }
  return 'Unbekannt';
}

const columnHelper = createColumnHelper();

const DEFAULT_TABLE_STATE = {
  sorting: [{ id: 'distanceKm', desc: false }],
  columnFilters: [{ id: 'membership', value: 'false' }]
};

function normalizePanelLayout(state) {
  const fallback = createDefaultPanelState();
  if (!state || typeof state !== 'object') {
    return fallback;
  }
  const rawOrder = Array.isArray(state.order) ? state.order : [];
  const normalizedOrder = rawOrder.filter((panelId) => PANEL_IDS.includes(panelId));
  const dedupedOrder = [...new Set([...normalizedOrder, ...PANEL_IDS])];
  const collapsed = { ...fallback.collapsed };
  PANEL_IDS.forEach((panelId) => {
    collapsed[panelId] = Boolean(state?.collapsed?.[panelId]);
  });
  return {
    order: dedupedOrder,
    collapsed
  };
}

function readPanelLayout() {
  if (typeof window === 'undefined') {
    return createDefaultPanelState();
  }
  try {
    const raw = window.localStorage.getItem(PANEL_STORAGE_KEY);
    if (!raw) {
      return createDefaultPanelState();
    }
    const parsed = JSON.parse(raw);
    return normalizePanelLayout(parsed);
  } catch {
    return createDefaultPanelState();
  }
}

function persistPanelLayout(state) {
  if (typeof window === 'undefined') {
    return;
  }
  try {
    const normalized = normalizePanelLayout(state);
    window.localStorage.setItem(PANEL_STORAGE_KEY, JSON.stringify(normalized));
  } catch {
    /* ignore */
  }
}

const ColumnTextFilter = ({ column, placeholder }) => {
  if (!column.getCanFilter()) {
    return null;
  }
  return (
    <input
      type="text"
      value={column.getFilterValue() ?? ''}
      onChange={(event) => column.setFilterValue(event.target.value)}
      placeholder={placeholder}
      className="mt-1 w-full rounded border px-2 py-1 text-xs focus:outline-none focus:ring-1 focus:ring-blue-500"
    />
  );
};

const ColumnSelectFilter = ({ column, options }) => {
  if (!column.getCanFilter()) {
    return null;
  }
  return (
    <select
      value={column.getFilterValue() ?? ''}
      onChange={(event) => column.setFilterValue(event.target.value || undefined)}
      className="mt-1 w-full rounded border px-2 py-1 text-xs focus:outline-none focus:ring-1 focus:ring-blue-500"
    >
      <option value="">Alle</option>
      {options.map((option) => (
        <option key={option.value} value={option.value}>
          {option.label}
        </option>
      ))}
    </select>
  );
};

function readWatchTableState() {
  if (typeof window === 'undefined') {
    return DEFAULT_TABLE_STATE;
  }
  try {
    const raw = window.localStorage.getItem(WATCH_TABLE_STATE_KEY);
    if (!raw) {
      return DEFAULT_TABLE_STATE;
    }
    const parsed = JSON.parse(raw);
    return {
      sorting: Array.isArray(parsed.sorting) && parsed.sorting.length > 0 ? parsed.sorting : DEFAULT_TABLE_STATE.sorting,
      columnFilters:
        Array.isArray(parsed.columnFilters) && parsed.columnFilters.length > 0
          ? parsed.columnFilters
          : DEFAULT_TABLE_STATE.columnFilters
    };
  } catch {
    return DEFAULT_TABLE_STATE;
  }
}

function persistWatchTableState(state) {
  if (typeof window === 'undefined') {
    return;
  }
  try {
    window.localStorage.setItem(WATCH_TABLE_STATE_KEY, JSON.stringify(state));
  } catch {
    /* ignore */
  }
}

const StoreWatchPage = ({
  authorizedFetch,
  knownStores = [],
  userLocation,
  locationLoading = false,
  locationError = '',
  notificationPanelOpen = false,
  onToggleNotificationPanel = () => {},
  notificationProps,
  isAdmin = false
}) => {
  const [regions, setRegions] = useState([]);
  const [selectedRegionId, setSelectedRegionId] = useState(() => {
    if (typeof window === 'undefined') {
      return 'all';
    }
    try {
      return window.localStorage.getItem(REGION_STORAGE_KEY) || 'all';
    } catch {
      return 'all';
    }
  });
  const [storesByRegion, setStoresByRegion] = useState({});
  const [watchList, setWatchList] = useState([]);
  const [regionLoading, setRegionLoading] = useState(false);
  const [storesLoading, setStoresLoading] = useState(false);
  const [subscriptionsLoading, setSubscriptionsLoading] = useState(false);
  const [status, setStatus] = useState('');
  const [error, setError] = useState('');
  const [dirty, setDirty] = useState(false);
  const [saving, setSaving] = useState(false);
  const [adhocChecking, setAdhocChecking] = useState(false);
  const [lastAdhocCheck, setLastAdhocCheck] = useState(null);
  const initialTableState = useMemo(() => readWatchTableState(), []);
  const [sorting, setSorting] = useState(initialTableState.sorting);
  const [columnFilters, setColumnFilters] = useState(initialTableState.columnFilters);
  const [panelLayout, setPanelLayout] = useState(() => readPanelLayout());
  const normalizedPanelLayout = useMemo(() => normalizePanelLayout(panelLayout), [panelLayout]);
  const panelOrder = normalizedPanelLayout.order;
  const aggregatedRegionStores = useMemo(() => {
    const list = [];
    Object.values(storesByRegion).forEach((entry) => {
      if (Array.isArray(entry?.stores)) {
        entry.stores.forEach((store) => {
          if (store) {
            list.push(store);
          }
        });
      }
    });
    return list;
  }, [storesByRegion]);
  const proximityLabel = useMemo(() => {
    if (!userLocation) {
      return null;
    }
    return inferLocationLabel(userLocation, aggregatedRegionStores);
  }, [userLocation, aggregatedRegionStores]);
  const displayLocation = useMemo(() => {
    if (!userLocation) {
      return null;
    }
    if (userLocation.label) {
      return userLocation;
    }
    if (proximityLabel) {
      return {
        ...userLocation,
        label: proximityLabel.label,
        labelDistanceKm: proximityLabel.distanceKm
      };
    }
    return userLocation;
  }, [userLocation, proximityLabel]);

  useEffect(() => {
    if (typeof window === 'undefined') {
      return;
    }
    try {
      window.localStorage.setItem(REGION_STORAGE_KEY, selectedRegionId || 'all');
    } catch {
      /* ignore */
    }
  }, [selectedRegionId]);

  useEffect(() => {
    persistWatchTableState({ sorting, columnFilters });
  }, [sorting, columnFilters]);
  useEffect(() => {
    persistPanelLayout(panelLayout);
  }, [panelLayout]);
  const togglePanelCollapsed = useCallback((panelId) => {
    if (!PANEL_IDS.includes(panelId)) {
      return;
    }
    setPanelLayout((prev) => {
      const normalized = normalizePanelLayout(prev);
      return {
        ...normalized,
        collapsed: {
          ...normalized.collapsed,
          [panelId]: !normalized.collapsed[panelId]
        }
      };
    });
  }, []);
  const movePanel = useCallback((panelId, direction) => {
    if (!PANEL_IDS.includes(panelId) || !direction) {
      return;
    }
    setPanelLayout((prev) => {
      const normalized = normalizePanelLayout(prev);
      const order = [...normalized.order];
      const currentIndex = order.indexOf(panelId);
      const delta = direction === 'up' ? -1 : 1;
      const nextIndex = currentIndex + delta;
      if (currentIndex === -1 || nextIndex < 0 || nextIndex >= order.length) {
        return normalized;
      }
      [order[currentIndex], order[nextIndex]] = [order[nextIndex], order[currentIndex]];
      return {
        ...normalized,
        order
      };
    });
  }, []);

  const watchedIds = useMemo(
    () => new Set(watchList.map((entry) => String(entry.storeId))),
    [watchList]
  );

  const selectedRegion = useMemo(() => {
    if (selectedRegionId === 'all') {
      return null;
    }
    return regions.find((region) => String(region.id) === String(selectedRegionId)) || null;
  }, [regions, selectedRegionId]);

  const activeRegionLabel = selectedRegionId === 'all' ? 'allen Regionen' : selectedRegion?.name || 'dieser Region';
  const storesPanelTitle = selectedRegionId === 'all' ? 'Betriebe' : `Betriebe in ${activeRegionLabel}`;

  const selectedStatusMeta = useMemo(() => {
    if (selectedRegionId === 'all') {
      const metas = regions
        .map((region) => storesByRegion[String(region.id)]?.statusMeta)
        .filter(Boolean);
      if (metas.length === 0) {
        return null;
      }
      const aggregated = metas.reduce(
        (acc, meta) => ({
          total: acc.total + (meta.total || 0),
          refreshed: acc.refreshed + (meta.refreshed || 0),
          fromCache: acc.fromCache + (meta.fromCache || 0),
          missing: acc.missing + (meta.missing || 0),
          generatedAt: Math.max(acc.generatedAt, meta.generatedAt || 0)
        }),
        { total: 0, refreshed: 0, fromCache: 0, missing: 0, generatedAt: 0 }
      );
      return aggregated;
    }
    return storesByRegion[String(selectedRegionId)]?.statusMeta || null;
  }, [selectedRegionId, storesByRegion, regions]);

  const lastUpdatedAt = useMemo(() => {
    if (selectedRegionId === 'all') {
      const timestamps = regions
        .map((region) => storesByRegion[String(region.id)]?.fetchedAt)
        .filter(Boolean);
      if (timestamps.length === 0) {
        return null;
      }
      return Math.max(...timestamps);
    }
    return storesByRegion[String(selectedRegionId)]?.fetchedAt || null;
  }, [regions, selectedRegionId, storesByRegion]);

  const currentStores = useMemo(() => {
    if (selectedRegionId === 'all') {
      const combined = new Map();
      regions.forEach((region) => {
        const entry = storesByRegion[String(region.id)];
        if (entry?.stores) {
          entry.stores.forEach((store) => {
            if (store?.id) {
              combined.set(String(store.id), store);
            }
          });
        }
      });
      return Array.from(combined.values());
    }
    const regionEntry = storesByRegion[String(selectedRegionId)];
    if (!regionEntry || !Array.isArray(regionEntry.stores)) {
      return [];
    }
    return regionEntry.stores;
  }, [regions, storesByRegion, selectedRegionId]);

  const regionStores = useMemo(
    () => currentStores.filter((store) => Number(store.cooperationStatus) === 5),
    [currentStores]
  );

  const statusSummary = useMemo(() => {
    if (!selectedStatusMeta) {
      return 'Team-Status noch nicht geladen.';
    }
    const parts = [
      `${selectedStatusMeta.refreshed || 0} aktualisiert`,
      `${selectedStatusMeta.fromCache || 0} aus Cache`
    ];
    if (selectedStatusMeta.missing) {
      parts.push(`${selectedStatusMeta.missing} ohne Daten`);
    }
    const timestamp = selectedStatusMeta.generatedAt
      ? new Date(selectedStatusMeta.generatedAt).toLocaleString('de-DE')
      : null;
    return `Team-Status: ${parts.join(', ')}${timestamp ? ` (Stand ${timestamp})` : ''}`;
  }, [selectedStatusMeta]);

  const membershipMap = useMemo(() => {
    const map = new Map();
    (knownStores || []).forEach((store) => {
      if (store?.id) {
        map.set(String(store.id), store);
      }
    });
    return map;
  }, [knownStores]);

  const handleToggleStore = useCallback(
    (store, checked) => {
      setWatchList((prev) => {
        const storeId = String(store.id || store.storeId);
        const existing = prev.find((entry) => entry.storeId === storeId);
        if (checked) {
          if (store.isOpen || existing) {
            return prev;
          }
          setDirty(true);
          const regionName = store.region?.name || selectedRegion?.name || existing?.regionName || '';
          return [
            ...prev,
            {
              storeId,
              storeName: store.name || store.storeName || `Store ${storeId}`,
              regionId: String(store.region?.id || selectedRegionId || existing?.regionId || ''),
              regionName,
              lastTeamSearchStatus: existing?.lastTeamSearchStatus ?? null
            }
          ];
        }
        if (!existing) {
          return prev;
        }
        setDirty(true);
        return prev.filter((entry) => entry.storeId !== storeId);
      });
    },
    [selectedRegion, selectedRegionId]
  );

  const handleRemoveWatch = useCallback((storeId) => {
    setWatchList((prev) => {
      const next = prev.filter((entry) => entry.storeId !== storeId);
      if (next.length !== prev.length) {
        setDirty(true);
      }
      return next;
    });
  }, []);

  const tableData = useMemo(
    () =>
      regionStores.map((store) => {
        const membership = membershipMap.has(String(store.id));
        const lat = Number(store.location?.lat);
        const lon = Number(store.location?.lon);
        const rawTeamStatus = store.teamStatus ?? store.teamSearchStatus;
        const statusValue = rawTeamStatus === null || rawTeamStatus === undefined
          ? null
          : Number(rawTeamStatus);
        const distance =
          userLocation && Number.isFinite(lat) && Number.isFinite(lon)
            ? haversineDistanceKm(userLocation.lat, userLocation.lon, lat, lon)
            : null;
        const isOpen = statusValue === 1;
        return {
          ...store,
          membership,
          distanceKm: distance,
          teamStatusUpdatedAt: store.teamStatusUpdatedAt || null,
          teamSearchStatus: statusValue,
          isOpen
        };
      }),
    [regionStores, membershipMap, userLocation]
  );

  const columns = useMemo(
    () => [
      columnHelper.accessor('name', {
        header: ({ column }) => (
          <div>
            <button
              type="button"
              className="flex w-full items-center justify-between text-left font-semibold"
              onClick={column.getToggleSortingHandler()}
            >
              <span>Betrieb</span>
              {column.getIsSorted() ? (
                <span className="text-xs text-gray-500">{column.getIsSorted() === 'asc' ? '▲' : '▼'}</span>
              ) : (
                <span className="text-xs text-gray-400">⇅</span>
              )}
            </button>
            <ColumnTextFilter column={column} placeholder="Name / ID" />
          </div>
        ),
        cell: ({ row }) => (
          <div className="flex items-start justify-between gap-3">
            <div>
              <p className="font-medium text-gray-900 flex items-center gap-2">
                {row.original.name}
              </p>
              <p className="text-xs text-gray-500">#{row.original.id}</p>
            </div>
            <a
              href={`https://foodsharing.de/store/${row.original.id}`}
              target="_blank"
              rel="noopener noreferrer"
              className="text-gray-400 hover:text-blue-600"
              title="Store öffnen"
            >
              <svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4" viewBox="0 0 20 20" fill="currentColor">
                <path d="M12.293 2.293a1 1 0 011.414 0L18 6.586V7a1 1 0 01-1 1h-.586l-3.707-3.707a1 1 0 010-1.414z" />
                <path d="M3 5a2 2 0 012-2h5a1 1 0 010 2H5v10h10v-5a1 1 0 112 0v5a2 2 0 01-2 2H5a2 2 0 01-2-2V5z" />
                <path d="M11 3a1 1 0 100 2h2v2a1 1 0 102 0V4a1 1 0 00-1-1h-3z" />
              </svg>
            </a>
          </div>
        ),
        sortingFn: 'alphanumeric',
        enableColumnFilter: true,
        filterFn: 'includesString'
      }),
      columnHelper.accessor((row) => row.city || '', {
        id: 'city',
        header: ({ column }) => (
          <div>
            <button
              type="button"
              className="flex w-full items-center justify-between text-left font-semibold"
              onClick={column.getToggleSortingHandler()}
            >
              <span>Ort</span>
              {column.getIsSorted() ? (
                <span className="text-xs text-gray-500">{column.getIsSorted() === 'asc' ? '▲' : '▼'}</span>
              ) : (
                <span className="text-xs text-gray-400">⇅</span>
              )}
            </button>
            <ColumnTextFilter column={column} placeholder="Ort / PLZ" />
          </div>
        ),
        cell: ({ row }) => (
          <div className="flex items-start justify-between gap-2">
            <div>
              <p className="text-gray-800 text-sm">{row.original.city || 'unbekannt'}</p>
              <p className="text-xs text-gray-500">{row.original.street || ''}</p>
            </div>
            {(() => {
              const hasUserLocation =
                userLocation &&
                Number.isFinite(userLocation.lat) &&
                Number.isFinite(userLocation.lon);
              const storeLat = Number(row.original.location?.lat);
              const storeLon = Number(row.original.location?.lon);
              const hasStoreLocation = Number.isFinite(storeLat) && Number.isFinite(storeLon);
              if (!hasUserLocation || !hasStoreLocation) {
                return null;
              }
              const origin = encodeURIComponent(`${userLocation.lat},${userLocation.lon}`);
              const storeLabel = row.original.name || row.original.city || `Store ${row.original.id}`;
              const destination = encodeURIComponent(`${storeLabel}@${storeLat},${storeLon}`);
              const mapsUrl = `https://www.google.com/maps/dir/?api=1&origin=${origin}&destination=${destination}&travelmode=driving`;
              return (
                <a
                  href={mapsUrl}
                  target="_blank"
                  rel="noopener noreferrer"
                  className="inline-flex h-6 w-6 items-center justify-center rounded text-gray-400 hover:text-blue-600"
                  title="Route zu diesem Betrieb in Google Maps öffnen"
                >
                  <span className="sr-only">Route in Google Maps</span>
                  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" className="h-4 w-4">
                    <path d="M12 2a6 6 0 00-6 6c0 4.2 6 12 6 12s6-7.8 6-12a6 6 0 00-6-6zm0 8a2 2 0 110-4 2 2 0 010 4z" />
                    <path d="M5 20.5a1 1 0 001.447.894l4.946-2.355a1 1 0 01.894 0l4.946 2.355A1 1 0 0019.68 20l-5.078-10.156" stroke="currentColor" strokeWidth="1.2" fill="none"/>
                  </svg>
                </a>
              );
            })()}
          </div>
        ),
        sortingFn: 'alphanumeric',
        filterFn: 'includesString'
      }),
      columnHelper.accessor('createdAt', {
        header: ({ column }) => (
          <button
            type="button"
            className="flex w-full items-center justify-between text-left font-semibold"
            onClick={column.getToggleSortingHandler()}
          >
            <span>Kooperation seit</span>
            {column.getIsSorted() ? (
              <span className="text-xs text-gray-500">{column.getIsSorted() === 'asc' ? '▲' : '▼'}</span>
            ) : (
              <span className="text-xs text-gray-400">⇅</span>
            )}
          </button>
        ),
        cell: ({ getValue }) => {
          const value = getValue();
          const label = value
            ? new Date(value).toLocaleDateString('de-DE', { year: 'numeric', month: '2-digit', day: '2-digit' })
            : '–';
          return <div className="text-center text-xs text-gray-700 tracking-wide">{label}</div>;
        },
        sortingFn: (rowA, rowB, columnId) => {
          const a = rowA.getValue(columnId);
          const b = rowB.getValue(columnId);
          return new Date(a || 0).getTime() - new Date(b || 0).getTime();
        }
      }),
      columnHelper.accessor('isOpen', {
        header: ({ column }) => (
          <div>
            <button
              type="button"
              className="flex w-full items-center justify-between text-left font-semibold"
              onClick={column.getToggleSortingHandler()}
            >
              <span>Offen</span>
              {column.getIsSorted() ? (
                <span className="text-xs text-gray-500">{column.getIsSorted() === 'asc' ? '▲' : '▼'}</span>
              ) : (
                <span className="text-xs text-gray-400">⇅</span>
              )}
            </button>
            <ColumnSelectFilter
              column={column}
              options={[
                { value: 'true', label: 'Ja' },
                { value: 'false', label: 'Nein' }
              ]}
            />
          </div>
        ),
        cell: ({ row, getValue }) => {
          const value = getValue();
          const updatedAt = row.original.teamStatusUpdatedAt
            ? new Date(row.original.teamStatusUpdatedAt).toLocaleDateString('de-DE')
            : null;
          if (value === null) {
            return <span className="text-sm text-gray-500">–</span>;
          }
          return (
            <div className="text-center">
              <span
                className={`inline-flex items-center justify-center rounded px-2 py-1 text-xs font-semibold ${
                  value ? 'bg-green-100 text-green-700' : 'bg-gray-100 text-gray-500'
                }`}
              >
                {value ? 'Ja' : 'Nein'}
              </span>
              {updatedAt && <p className="text-[10px] text-gray-500 mt-0.5">{updatedAt}</p>}
            </div>
          );
        },
        filterFn: (row, columnId, value) => {
          if (value === undefined) {
            return true;
          }
          const boolValue = value === 'true';
          return row.getValue(columnId) === boolValue;
        },
        sortingFn: (rowA, rowB, columnId) => {
          const a = rowA.getValue(columnId);
          const b = rowB.getValue(columnId);
          return Number(b) - Number(a);
        }
      }),
      columnHelper.accessor('membership', {
        header: ({ column }) => (
          <div>
            <button
              type="button"
              className="flex w-full items-center justify-between text-left font-semibold"
              onClick={column.getToggleSortingHandler()}
            >
              <span>Mitglied</span>
              {column.getIsSorted() ? (
                <span className="text-xs text-gray-500">{column.getIsSorted() === 'asc' ? '▲' : '▼'}</span>
              ) : (
                <span className="text-xs text-gray-400">⇅</span>
              )}
            </button>
            <ColumnSelectFilter
              column={column}
              options={[
                { value: 'true', label: 'Ja' },
                { value: 'false', label: 'Nein' }
              ]}
            />
          </div>
        ),
        cell: ({ getValue }) => {
          const value = getValue();
          return (
            <span
              className={`inline-flex items-center justify-center rounded px-2 py-1 text-xs font-semibold ${
                value ? 'bg-green-100 text-green-700' : 'bg-gray-100 text-gray-500'
              }`}
            >
              {value ? 'Ja' : 'Nein'}
            </span>
          );
        },
        filterFn: (row, columnId, value) => {
          if (value === undefined) {
            return true;
          }
          const boolValue = value === 'true';
          return row.getValue(columnId) === boolValue;
        },
        sortingFn: (rowA, rowB, columnId) => {
          const a = rowA.getValue(columnId);
          const b = rowB.getValue(columnId);
          return Number(b) - Number(a);
        }
      }),
      columnHelper.accessor('distanceKm', {
        header: ({ column }) => (
          <div>
            <button
              type="button"
              className="flex w-full items-center justify-between text-left font-semibold disabled:cursor-not-allowed disabled:text-gray-400"
              onClick={userLocation ? column.getToggleSortingHandler() : undefined}
              disabled={!userLocation}
            >
              <span>Entfernung</span>
              {column.getIsSorted() ? (
                <span className="text-xs text-gray-500">{column.getIsSorted() === 'asc' ? '▲' : '▼'}</span>
              ) : (
                <span className="text-xs text-gray-400">⇅</span>
              )}
            </button>
            {!userLocation && <p className="mt-1 text-xs text-gray-500">Standort erforderlich</p>}
          </div>
        ),
        cell: ({ getValue }) => {
          const value = getValue();
          if (!value && value !== 0) {
            return <span className="text-sm text-gray-500">–</span>;
          }
          return <span className="text-sm text-gray-800">{value.toFixed(2)} km</span>;
        },
        sortingFn: (rowA, rowB, columnId) => {
          const a = rowA.getValue(columnId);
          const b = rowB.getValue(columnId);
          if (a === null || a === undefined) {
            return 1;
          }
          if (b === null || b === undefined) {
            return -1;
          }
          return a - b;
        },
        enableColumnFilter: false,
        enableSorting: !!userLocation
      }),
      columnHelper.display({
        id: 'watch',
        header: () => <span>Überwachen</span>,
        cell: ({ row }) => {
          const store = row.original;
          const checked = watchedIds.has(String(store.id));
          const disabled = store.isOpen;
          return (
            <div className="text-center">
              <input
                type="checkbox"
                className="h-5 w-5"
                checked={checked}
                onChange={(event) => handleToggleStore(store, event.target.checked)}
                disabled={disabled}
                title={
                  disabled ? 'Store ist bereits offen – Überwachung nicht verfügbar.' : undefined
                }
              />
            </div>
          );
        }
      })
    ],
    [handleToggleStore, watchedIds, userLocation]
  );

  const table = useReactTable({
    data: tableData,
    columns,
    state: {
      sorting,
      columnFilters
    },
    onSortingChange: setSorting,
    onColumnFiltersChange: setColumnFilters,
    getCoreRowModel: getCoreRowModel(),
    getSortedRowModel: getSortedRowModel(),
    getFilteredRowModel: getFilteredRowModel()
  });

  const loadRegions = useCallback(async () => {
    if (!authorizedFetch) {
      return;
    }
    setRegionLoading(true);
    setError('');
    try {
      const response = await authorizedFetch('/api/store-watch/regions');
      if (!response.ok) {
        throw new Error(`HTTP ${response.status}`);
      }
      const data = await response.json();
      const normalized = Array.isArray(data.regions) ? data.regions : [];
      setRegions(normalized);
      setSelectedRegionId((prev) => {
        if (!prev) {
          return 'all';
        }
        if (prev === 'all') {
          return prev;
        }
        const exists = normalized.some((region) => String(region.id) === String(prev));
        if (!exists) {
          return normalized.length > 0 ? String(normalized[0].id) : 'all';
        }
        return prev;
      });
    } catch (err) {
      setError(`Regionen konnten nicht geladen werden: ${err.message}`);
    } finally {
      setRegionLoading(false);
    }
  }, [authorizedFetch]);

  const loadSubscriptions = useCallback(async () => {
    if (!authorizedFetch) {
      return;
    }
    setSubscriptionsLoading(true);
    setError('');
    try {
      const response = await authorizedFetch('/api/store-watch/subscriptions');
      if (!response.ok) {
        throw new Error(`HTTP ${response.status}`);
      }
      const data = await response.json();
      const normalized = Array.isArray(data.stores) ? data.stores : [];
      setWatchList(normalized);
      setDirty(false);
    } catch (err) {
      setError(`Überwachte Betriebe konnten nicht geladen werden: ${err.message}`);
    } finally {
      setSubscriptionsLoading(false);
    }
  }, [authorizedFetch]);

  const fetchStoresForRegion = useCallback(
    async (regionId, { force, silent, forceStatus } = {}) => {
      if (!authorizedFetch || !regionId) {
        return;
      }
      if (!force && !forceStatus && storesByRegion[String(regionId)]) {
        return;
      }
      if (!silent) {
        setStoresLoading(true);
      }
      setError('');
      try {
        const params = new URLSearchParams();
        if (force) {
          params.append('force', '1');
        }
        if (forceStatus) {
          params.append('forceStatus', '1');
        }
        const qs = params.toString();
        const endpoint = `/api/store-watch/regions/${regionId}/stores${qs ? `?${qs}` : ''}`;
        const response = await authorizedFetch(endpoint);
        if (!response.ok) {
          throw new Error(`HTTP ${response.status}`);
        }
        const data = await response.json();
        setStoresByRegion((prev) => ({
          ...prev,
          [String(regionId)]: {
            total: Number(data.total) || 0,
            stores: Array.isArray(data.stores) ? data.stores : [],
            fetchedAt: Date.now(),
            statusMeta: data.statusMeta || null
          }
        }));
      } catch (err) {
        setError(`Betriebe konnten nicht geladen werden: ${err.message}`);
      } finally {
        if (!silent) {
          setStoresLoading(false);
        }
      }
    },
    [authorizedFetch, storesByRegion]
  );

  const fetchAllRegions = useCallback(
    async ({ force, forceStatus } = {}) => {
      if (!authorizedFetch || regions.length === 0) {
        return;
      }
      const targets = regions.filter(
        (region) => force || forceStatus || !storesByRegion[String(region.id)]
      );
      if (targets.length === 0) {
        return;
      }
      setStoresLoading(true);
      setError('');
      try {
        for (const region of targets) {
          await fetchStoresForRegion(region.id, { force, silent: true, forceStatus });
        }
      } catch (err) {
        setError(`Betriebe konnten nicht geladen werden: ${err.message}`);
      } finally {
        setStoresLoading(false);
      }
    },
    [authorizedFetch, regions, storesByRegion, fetchStoresForRegion]
  );

  useEffect(() => {
    loadRegions();
    loadSubscriptions();
  }, [loadRegions, loadSubscriptions]);

  useEffect(() => {
    if (!selectedRegionId) {
      return;
    }
    if (selectedRegionId === 'all') {
      fetchAllRegions({ force: false });
    } else {
      fetchStoresForRegion(selectedRegionId);
    }
  }, [selectedRegionId, fetchStoresForRegion, fetchAllRegions]);

  const handleSave = useCallback(async () => {
    if (!authorizedFetch || saving || !dirty) {
      return;
    }
    setSaving(true);
    setStatus('');
    setError('');
    try {
      const response = await authorizedFetch('/api/store-watch/subscriptions', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ stores: watchList })
      });
      if (!response.ok) {
        throw new Error(`HTTP ${response.status}`);
      }
      const data = await response.json();
      setWatchList(Array.isArray(data.stores) ? data.stores : []);
      setDirty(false);
      setStatus('Überwachung gespeichert.');
      setTimeout(() => setStatus(''), 4000);
    } catch (err) {
      setError(`Speichern fehlgeschlagen: ${err.message}`);
    } finally {
      setSaving(false);
    }
  }, [authorizedFetch, dirty, saving, watchList]);

  const handleReset = useCallback(() => {
    loadSubscriptions();
  }, [loadSubscriptions]);

  const handleStatusRefresh = useCallback(() => {
    if (selectedRegionId === 'all') {
      fetchAllRegions({ force: true, forceStatus: true });
    } else if (selectedRegionId) {
      fetchStoresForRegion(selectedRegionId, { forceStatus: true });
    }
  }, [selectedRegionId, fetchAllRegions, fetchStoresForRegion]);
  const handleAdhocWatchCheck = useCallback(async () => {
    if (!authorizedFetch || adhocChecking || watchList.length === 0) {
      return;
    }
    setAdhocChecking(true);
    setError('');
    try {
      const response = await authorizedFetch('/api/store-watch/check', { method: 'POST' });
      if (!response.ok) {
        throw new Error(`HTTP ${response.status}`);
      }
      const data = await response.json();
      const summary = Array.isArray(data.stores) ? data.stores : [];
      setLastAdhocCheck({
        checkedAt: Date.now(),
        stores: summary
      });
      setStatus('Aktualisierung abgeschlossen. Zusammenfassung versendet.');
      setTimeout(() => setStatus(''), 4000);
      await loadSubscriptions();
    } catch (err) {
      setError(`Aktualisierung fehlgeschlagen: ${err.message}`);
    } finally {
      setAdhocChecking(false);
    }
  }, [authorizedFetch, adhocChecking, watchList.length, loadSubscriptions]);
  const panelTitles = {
    stores: storesPanelTitle,
    watch: `Überwachte Betriebe (${watchList.length})`
  };
  const renderPanelRightContent = (panelId) => {
    if (panelId === 'stores') {
      if (!lastUpdatedAt) {
        return null;
      }
      return (
        <span className="text-xs text-gray-500">
          Aktualisiert: {new Date(lastUpdatedAt).toLocaleTimeString('de-DE')}
        </span>
      );
    }
    if (panelId === 'watch') {
      return (
        <div className="flex flex-wrap gap-2">
          <button
            type="button"
            className="px-4 py-2 border rounded-md text-sm bg-white hover:bg-gray-100 disabled:opacity-60"
            onClick={handleAdhocWatchCheck}
            disabled={adhocChecking || subscriptionsLoading || watchList.length === 0}
          >
            {adhocChecking ? 'Aktualisiere...' : 'Aktualisieren'}
          </button>
          <button
            type="button"
            className="px-4 py-2 border rounded-md text-sm bg-white hover:bg-gray-100"
            onClick={handleReset}
            disabled={subscriptionsLoading}
          >
            Änderungen verwerfen
          </button>
          <button
            type="button"
            className="px-4 py-2 rounded-md text-sm text-white bg-blue-600 hover:bg-blue-700 disabled:opacity-60"
            onClick={handleSave}
            disabled={!dirty || saving}
          >
            {saving ? 'Speichere...' : 'Speichern'}
          </button>
        </div>
      );
    }
    return null;
  };
  const renderPanelContent = (panelId) => {
    if (panelId === 'stores') {
      return (
        <>
          {storesLoading && <p className="text-sm text-gray-600">Lade Betriebe...</p>}
          {!storesLoading && table.getRowModel().rows.length === 0 && (
            <p className="text-sm text-gray-500">
              Keine Betriebe gefunden. Prüfe Filter oder sortiere anders.
            </p>
          )}
          {!storesLoading && table.getRowModel().rows.length > 0 && (
            <div className="overflow-x-auto border border-gray-200 rounded-lg">
              <table className="min-w-full divide-y divide-gray-200 text-sm">
                <thead className="bg-gray-100">
                  {table.getHeaderGroups().map((headerGroup) => (
                    <tr key={headerGroup.id}>
                      {headerGroup.headers.map((header) => (
                        <th key={header.id} className="px-4 py-2 text-left align-top text-sm font-semibold">
                          {flexRender(header.column.columnDef.header, header.getContext())}
                        </th>
                      ))}
                    </tr>
                  ))}
                </thead>
                <tbody className="divide-y divide-gray-200">
                  {table.getRowModel().rows.map((row) => (
                    <tr key={row.id} className="bg-white">
                      {row.getVisibleCells().map((cell) => (
                        <td key={cell.id} className="px-4 py-2 align-middle">
                          {flexRender(cell.column.columnDef.cell, cell.getContext())}
                        </td>
                      ))}
                    </tr>
                  ))}
                  {table.getRowModel().rows.length === 0 && (
                    <tr>
                      <td
                        className="px-4 py-6 text-center text-sm text-gray-500"
                        colSpan={table.getHeaderGroups()?.[0]?.headers.length || 1}
                      >
                        Keine Betriebe entsprechen den aktuellen Filtern.
                      </td>
                    </tr>
                  )}
                </tbody>
              </table>
            </div>
          )}
        </>
      );
    }
    if (panelId === 'watch') {
      return (
        <>
          {subscriptionsLoading && <p className="text-sm text-gray-600">Lade aktuelle Auswahl...</p>}
          {!subscriptionsLoading && watchList.length === 0 && (
            <p className="text-sm text-gray-500">Noch keine Betriebe ausgewählt.</p>
          )}
          {watchList.length > 0 && (
            <div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
              {watchList.map((entry) => (
                <div key={entry.storeId} className="border border-gray-200 rounded-lg p-3 bg-gray-50">
                  <div className="flex justify-between items-start">
                    <div>
                      <p className="font-semibold text-gray-900">{entry.storeName}</p>
                      <p className="text-xs text-gray-500">
                        #{entry.storeId} — {entry.regionName || 'Region unbekannt'}
                      </p>
                    </div>
                    <button
                      type="button"
                      className="text-xs text-red-600 hover:underline"
                      onClick={() => handleRemoveWatch(entry.storeId)}
                    >
                      Entfernen
                    </button>
                  </div>
                  <p className="text-xs text-gray-600 mt-2">
                    Letzter Status:{' '}
                    {formatWatchStatusLabel(entry.lastTeamSearchStatus)}{' '}
                    {entry.lastStatusCheckAt
                      ? `(geprüft am ${new Date(entry.lastStatusCheckAt).toLocaleString('de-DE')})`
                      : '(noch nicht geprüft)'}
                  </p>
                </div>
              ))}
            </div>
          )}
          {lastAdhocCheck?.stores?.length > 0 && (
            <div className="mt-4 rounded-lg border border-blue-100 bg-blue-50 p-3 text-sm text-blue-900">
              <p className="text-xs font-semibold text-blue-800">
                Letzte Aktualisierung:{' '}
                {new Date(lastAdhocCheck.checkedAt).toLocaleString('de-DE')}
              </p>
              <ul className="mt-2 space-y-1 text-xs">
                {lastAdhocCheck.stores.map((entry, index) => {
                  const statusLabel = formatWatchStatusLabel(entry.status);
                  const timestamp = entry.checkedAt
                    ? new Date(entry.checkedAt).toLocaleString('de-DE')
                    : null;
                  return (
                    <li key={`${entry.storeId}-${index}`}>
                      <span className="font-semibold">
                        {entry.storeName || `#${entry.storeId}`}
                      </span>
                      <span className="text-blue-800">
                        {entry.regionName ? ` (${entry.regionName})` : ''}
                      </span>
                      : {statusLabel}
                      {timestamp ? ` — ${timestamp}` : ''}
                      {entry.error ? ` — Fehler: ${entry.error}` : ''}
                    </li>
                  );
                })}
              </ul>
            </div>
          )}
        </>
      );
    }
    return null;
  };

  if (!authorizedFetch) {
    return (
      <div className="p-4 max-w-6xl w-full mx-auto">
        <p className="text-red-600">Keine Session aktiv.</p>
      </div>
    );
  }

  return (
    <div className="p-4 max-w-6xl w-full mx-auto bg-white shadow rounded-lg mt-4">
      <div className="flex flex-col gap-2 mb-4">
        <h1 className="text-2xl font-bold text-blue-900">Betriebs-Monitoring</h1>
        <p className="text-gray-600 text-sm">
          Wähle Betriebe aus, die bei offenem Team-Status automatisch gemeldet werden sollen.
        </p>
      </div>

      <div className="mb-4 flex flex-wrap items-center justify-end gap-2">
        <button
          type="button"
          onClick={onToggleNotificationPanel}
          className={`flex items-center justify-center w-11 h-11 rounded-full border ${
            notificationPanelOpen ? 'border-blue-500 text-blue-600' : 'border-gray-300 text-gray-600'
          } hover:text-blue-700 hover:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-400 transition`}
          title="Benachrichtigungen konfigurieren"
        >
          <svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
            <path
              strokeLinecap="round"
              strokeLinejoin="round"
              strokeWidth={2}
              d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 0 0 2.573 1.066c1.543-.89 3.31.877 2.42 2.42a1.724 1.724 0 0 0 1.065 2.572c1.757.426 1.757 2.924 0 3.35a1.724 1.724 0 0 0-1.066 2.573c.89 1.543-.877 3.31-2.42 2.42a1.724 1.724 0 0 0-2.572 1.065c-.426 1.757-2.924 1.757-3.35 0a1.724 1.724 0 0 0-2.573-1.066c-1.543.89-3.31-.877-2.42-2.42a1.724 1.724 0 0 0-1.065-2.572c-1.757-.426-1.757-2.924 0-3.35a1.724 1.724 0 0 0 1.066-2.573c-.89-1.543.877-3.31 2.42-2.42.996.575 2.273.155 2.573-1.065z"
            />
            <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0z" />
          </svg>
        </button>
        {notificationProps?.loading && <span className="text-sm text-gray-500">Lade…</span>}
      </div>

      {notificationPanelOpen && notificationProps && (
        <NotificationPanel
          {...notificationProps}
          location={displayLocation}
          locationLoading={locationLoading}
          locationError={locationError}
        />
      )}

      {(error || status) && (
        <div className="mb-4 space-y-2">
          {error && (
            <div className="bg-red-100 border border-red-300 text-red-700 px-4 py-2 rounded">{error}</div>
          )}
          {status && (
            <div className="bg-green-100 border border-green-300 text-green-700 px-4 py-2 rounded">
              {status}
            </div>
          )}
        </div>
      )}

      {!userLocation && !locationLoading && (
        <div className="mb-6 rounded-lg border border-blue-200 bg-blue-50 p-4 text-sm text-blue-900">
          <p>
            Standortdaten für die Entfernungssortierung stammen automatisch aus deinem Foodsharing-Profil. Ergänze
            dort deine Koordinaten, falls sie fehlen.
          </p>
        </div>
      )}

      <div className="mb-6 border border-gray-200 rounded-lg p-4 bg-gray-50">
        <div className="flex flex-col md:flex-row md:items-end gap-3">
          <div className="flex-1">
            <label className="block text-sm font-medium text-gray-700 mb-1" htmlFor="region-select">
              Region
            </label>
            <select
              id="region-select"
              value={selectedRegionId}
              onChange={(event) => setSelectedRegionId(event.target.value || 'all')}
              className="border rounded-md p-2 w-full"
              disabled={regionLoading}
            >
              <option value="all">Alle Regionen</option>
              {regions.map((region) => (
                <option key={region.id} value={region.id}>
                  {region.name}
                </option>
              ))}
            </select>
          </div>
          {isAdmin && (
            <div className="flex flex-wrap gap-2">
              <button
                type="button"
                onClick={() => loadRegions()}
                className="px-4 py-2 border rounded-md text-sm bg-white hover:bg-gray-100"
                disabled={regionLoading}
              >
                Regionen neu laden
              </button>
              <button
                type="button"
                onClick={() =>
                  selectedRegionId === 'all'
                    ? fetchAllRegions({ force: true })
                    : fetchStoresForRegion(selectedRegionId, { force: true })
                }
                className="px-4 py-2 border rounded-md text-sm bg-white hover:bg-gray-100"
                disabled={regionLoading || storesLoading || (selectedRegionId === 'all' && regions.length === 0)}
              >
                Betriebe aktualisieren
              </button>
              <button
                type="button"
                onClick={handleStatusRefresh}
                className="px-4 py-2 border rounded-md text-sm bg-white hover:bg-gray-100"
                disabled={regionLoading || (selectedRegionId === 'all' && regions.length === 0)}
              >
                Team-Status aktualisieren
              </button>
            </div>
          )}
        </div>
        <div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-2 mt-2 text-xs text-gray-500">
          <span>Es werden nur Regionen angezeigt, in denen du Mitglied mit Klassifikation 1 bist.</span>
          <span>{statusSummary}</span>
        </div>
      </div>

      {panelOrder.map((panelId) => {
        const collapsed = Boolean(normalizedPanelLayout.collapsed?.[panelId]);
        const title = panelTitles[panelId] || panelId;
        const panelIndex = panelOrder.indexOf(panelId);
        const canMoveUp = panelIndex > 0;
        const canMoveDown = panelIndex < panelOrder.length - 1;
        const rightContent = renderPanelRightContent(panelId);
        const showRightColumn = Boolean(rightContent) || (collapsed && panelOrder.length > 1);
        return (
          <section key={panelId} className="mb-6 border border-gray-200 rounded-lg overflow-hidden bg-white">
            <div className="flex flex-col gap-2 border-b border-gray-200 bg-gray-50 px-4 py-3 sm:flex-row sm:items-center sm:justify-between">
              <button
                type="button"
                className="flex items-center gap-2 text-left text-gray-800 focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 rounded"
                onClick={() => togglePanelCollapsed(panelId)}
                aria-expanded={!collapsed}
              >
                <span className="text-sm text-gray-500">{collapsed ? '▶' : '▼'}</span>
                <span className="text-lg font-semibold">{title}</span>
              </button>
              {showRightColumn && (
                <div className="flex flex-wrap items-center gap-2 justify-end">
                  {rightContent}
                  {collapsed && panelOrder.length > 1 && (
                    <div className="flex items-center gap-1 text-xs text-gray-500">
                      <span className="hidden sm:inline">Reihenfolge:</span>
                      <div className="flex gap-1">
                        <button
                          type="button"
                          className="px-2 py-1 border rounded disabled:opacity-40"
                          onClick={() => movePanel(panelId, 'up')}
                          disabled={!canMoveUp}
                          title="Nach oben"
                        >
                          ↑
                        </button>
                        <button
                          type="button"
                          className="px-2 py-1 border rounded disabled:opacity-40"
                          onClick={() => movePanel(panelId, 'down')}
                          disabled={!canMoveDown}
                          title="Nach unten"
                        >
                          ↓
                        </button>
                      </div>
                    </div>
                  )}
                </div>
              )}
            </div>
            {!collapsed && <div className="p-4">{renderPanelContent(panelId)}</div>}
            {collapsed && (
              <div className="px-4 py-3 text-xs text-gray-500">
                Bereich ist eingeklappt. Über die Pfeile kann die Reihenfolge angepasst werden.
              </div>
            )}
          </section>
        );
      })}

      {dirty && (
        <p className="text-xs text-amber-600">
          Es gibt ungespeicherte Änderungen. Bitte "Speichern" klicken.
        </p>
      )}
    </div>
  );
};

export default StoreWatchPage;
