import { useCallback } from 'react';

const useStoreSync = ({
  sessionToken,
  authorizedFetch,
  setStatus,
  setError,
  setLoading,
  setStores,
  setRegularPickupMap,
  setConfig,
  normalizeConfigEntries,
  setIsDirty,
  startSyncProgress,
  updateSyncProgress,
  finishSyncProgress
}) => {
  const delay = useCallback((ms) => new Promise((resolve) => setTimeout(resolve, ms)), []);

  const fetchConfig = useCallback(
    async (tokenOverride, { silent = false } = {}) => {
      const tokenToUse = tokenOverride || sessionToken;
      if (!tokenToUse) {
        return;
      }
      if (!silent) {
        setStatus('');
        setLoading(true);
      }
      setError('');
      try {
        const response = await authorizedFetch('/api/config', {}, tokenToUse);
        if (!response.ok) {
          throw new Error(`HTTP ${response.status}`);
        }
        const data = await response.json();
        setConfig(normalizeConfigEntries(Array.isArray(data) ? data : []));
        if (!silent) {
          setStatus('Konfiguration aktualisiert.');
          setTimeout(() => setStatus(''), 3000);
        }
      } catch (err) {
        setError(`Fehler beim Laden der Konfiguration: ${err.message}`);
      } finally {
        if (!silent) {
          setLoading(false);
        }
      }
    },
    [sessionToken, authorizedFetch, setStatus, setLoading, setError, setConfig, normalizeConfigEntries]
  );

  const fetchStoresList = useCallback(
    async (tokenOverride, { silent = false } = {}) => {
      const tokenToUse = tokenOverride || sessionToken;
      if (!tokenToUse) {
        return;
      }
      if (!silent) {
        setStatus('');
      }
      setError('');
      try {
        const response = await authorizedFetch('/api/stores', {}, tokenToUse);
        if (!response.ok) {
          throw new Error(`HTTP ${response.status}`);
        }
        const data = await response.json();
        if (Array.isArray(data)) {
          setStores(data);
        } else {
          setStores(Array.isArray(data?.stores) ? data.stores : []);
          if (data?.regularPickupMap && typeof data.regularPickupMap === 'object') {
            setRegularPickupMap(data.regularPickupMap);
          }
        }
        if (!silent) {
          setStatus('Betriebe aktualisiert.');
          setTimeout(() => setStatus(''), 3000);
        }
      } catch (err) {
        setError(`Fehler beim Laden der Betriebe: ${err.message}`);
      }
    },
    [sessionToken, authorizedFetch, setStatus, setError, setStores, setRegularPickupMap]
  );

  const syncStoresWithProgress = useCallback(
    async ({ block = false, reason = 'manual', startJob = true, reuseOverlay = false, tokenOverride } = {}) => {
      const effectiveToken = tokenOverride || sessionToken;
      if (!effectiveToken) {
        return;
      }
      if (!reuseOverlay) {
        startSyncProgress('Betriebe werden geprüft...', 5, block);
      } else {
        updateSyncProgress('Betriebe werden geprüft...', 35);
      }
      try {
        let jobStarted = false;
        const jobStartedAt = Date.now();
        const triggerRefresh = async () => {
          const response = await authorizedFetch(
            '/api/stores/refresh',
            {
              method: 'POST',
              headers: { 'Content-Type': 'application/json' },
              body: JSON.stringify({ force: true, reason })
            },
            effectiveToken
          );
          if (!response.ok) {
            throw new Error(`HTTP ${response.status}`);
          }
          await response.json();
          jobStarted = true;
        };

        if (startJob) {
          await triggerRefresh();
        }

        let completed = false;
        while (!completed) {
          const statusResp = await authorizedFetch('/api/stores/refresh/status', {}, effectiveToken);
          if (!statusResp.ok) {
            throw new Error(`HTTP ${statusResp.status}`);
          }
          const statusData = await statusResp.json();
          const job = statusData.job;
          if (job?.status === 'running') {
            const total = job.total || 0;
            const processed = job.processed || 0;
            let percent;
            if (total > 0) {
              const ratio = Math.max(0, Math.min(1, processed / total));
              percent = Math.min(99, 5 + Math.round(ratio * 90));
            }
            let etaSeconds = null;
            if (total > 0 && processed > 0) {
              const elapsedSeconds = Math.max(1, (Date.now() - jobStartedAt) / 1000);
              const rate = processed / elapsedSeconds;
              if (rate > 0) {
                const remaining = Math.max(0, total - processed);
                etaSeconds = Math.round(remaining / rate);
              }
            }
            const message = job.currentStore
              ? `Prüfe ${job.currentStore} (${processed}/${total || '?'})`
              : 'Betriebe werden geprüft...';
            updateSyncProgress(message, percent, { etaSeconds });
          } else if (!job) {
            if (statusData.storesFresh) {
              updateSyncProgress('Betriebe aktuell.', 99, { etaSeconds: null });
              completed = true;
            } else if (!jobStarted) {
              await triggerRefresh();
              await delay(500);
            } else {
              updateSyncProgress('Warte auf Rückmeldung...', undefined, { etaSeconds: null });
            }
          } else if (job.status === 'done') {
            updateSyncProgress('Synchronisierung abgeschlossen', 100, { etaSeconds: null });
            completed = true;
          } else if (job.status === 'error') {
            throw new Error(job.error || 'Unbekannter Fehler beim Prüfen der Betriebe.');
          }
          if (!completed) {
            await delay(1000);
          }
        }

        await fetchStoresList(effectiveToken, { silent: reason !== 'manual' });
        await fetchConfig(effectiveToken, { silent: true });
        setIsDirty(false);
        setStatus('Betriebe aktualisiert.');
        setTimeout(() => setStatus(''), 3000);
      } catch (err) {
        setError(`Aktualisieren der Betriebe fehlgeschlagen: ${err.message}`);
      } finally {
        if (!reuseOverlay) {
          finishSyncProgress();
        }
      }
    },
    [
      sessionToken,
      authorizedFetch,
      startSyncProgress,
      updateSyncProgress,
      finishSyncProgress,
      delay,
      fetchStoresList,
      fetchConfig,
      setIsDirty,
      setStatus,
      setError
    ]
  );

  const refreshStoresAndConfig = useCallback(
    ({ block = false } = {}) => syncStoresWithProgress({ block, reason: 'manual', startJob: true }),
    [syncStoresWithProgress]
  );

  return {
    fetchConfig,
    fetchStoresList,
    syncStoresWithProgress,
    refreshStoresAndConfig
  };
};

export default useStoreSync;
