// Couche API — appels vers le backend PHP/MySQL

(function () {
  window.API_BASE = (window.API_CONFIG?.base || '') + '/api';
})();

async function apiCall(path, options = {}) {
  const token = localStorage.getItem('maisonnee:token') || '';
  const res = await fetch(window.API_BASE + path, {
    headers: {
      'Content-Type': 'application/json',
      'X-Token': token,
      ...(options.headers || {}),
    },
    ...options,
  });
  const data = await res.json().catch(() => ({}));
  if (!res.ok) throw new Error(data.error || `Erreur ${res.status}`);
  return data;
}

// ── Auth ─────────────────────────────────────────────

function useAuthSB() {
  const [user, setUser] = React.useState(() => {
    try { return localStorage.getItem('maisonnee:user') || null; } catch { return null; }
  });
  const [loading] = React.useState(false);

  const login = async (key) => {
    const data = await apiCall('/auth.php', {
      method: 'POST',
      body: JSON.stringify({ username: key, password: key }),
    });
    localStorage.setItem('maisonnee:token', data.token);
    localStorage.setItem('maisonnee:user',  data.user);
    setUser(data.user);
  };

  const logout = async () => {
    try { await apiCall('/auth.php', { method: 'DELETE' }); } catch {}
    localStorage.removeItem('maisonnee:token');
    localStorage.removeItem('maisonnee:user');
    localStorage.removeItem('maisonnee:items');
    setUser(null);
  };

  return { user, login, logout, loading };
}

// ── Store ─────────────────────────────────────────────

function useStoreSB() {
  const [items, setItems] = React.useState(() => {
    try {
      const raw = localStorage.getItem('maisonnee:items');
      if (raw) return JSON.parse(raw);
    } catch {}
    return [];
  });
  const [synced,    setSynced]    = React.useState(false);
  const [syncError, setSyncError] = React.useState(null);

  // IDs des items en cours d'écriture → le polling ne doit pas les écraser
  const pendingRef = React.useRef(new Set());

  const loadItems = React.useCallback(async () => {
    if (!localStorage.getItem('maisonnee:token')) return;
    try {
      const data = await apiCall('/items.php');
      const serverItems = Array.isArray(data) ? data : [];

      // Serveur vide mais localStorage a des items → on les remonte
      if (serverItems.length === 0) {
        let localItems = [];
        try { localItems = JSON.parse(localStorage.getItem('maisonnee:items') || '[]'); } catch {}
        if (localItems.length > 0) {
          await Promise.all(localItems.map(it =>
            apiCall('/items.php', { method: 'POST', body: JSON.stringify(it) }).catch(() => {})
          ));
          const fresh = await apiCall('/items.php');
          setItems(Array.isArray(fresh) ? fresh : localItems);
          setSynced(true);
          setSyncError(null);
          return;
        }
      }

      // Fusion : on ne touche pas aux items dont le POST est encore en vol
      setItems(prev => {
        const pending = pendingRef.current;
        if (pending.size === 0) return serverItems;
        const prevMap = new Map(prev.map(x => [x.id, x]));
        const serverIds = new Set(serverItems.map(x => x.id));
        const merged = serverItems.map(s =>
          pending.has(s.id) ? (prevMap.get(s.id) || s) : s
        );
        // Items locaux pending pas encore confirmés par le serveur
        prev.forEach(loc => {
          if (pending.has(loc.id) && !serverIds.has(loc.id)) merged.push(loc);
        });
        return merged;
      });

      setSynced(true);
      setSyncError(null);
    } catch (e) {
      setSyncError(e.message);
      setSynced(true);
    }
  }, []);

  // Chargement initial + reset au changement de session
  React.useEffect(() => {
    const token = localStorage.getItem('maisonnee:token');
    if (!token) { setItems([]); return; }
    loadItems();
  }, [loadItems]);

  // Synchro cross-appareils : polling 10s + focus
  React.useEffect(() => {
    const interval = setInterval(() => {
      if (!document.hidden) loadItems();
    }, 10000);
    const onVisible = () => { if (!document.hidden) loadItems(); };
    const onFocus   = () => loadItems();
    document.addEventListener('visibilitychange', onVisible);
    window.addEventListener('focus', onFocus);
    return () => {
      clearInterval(interval);
      document.removeEventListener('visibilitychange', onVisible);
      window.removeEventListener('focus', onFocus);
    };
  }, [loadItems]);

  // Cache local
  React.useEffect(() => {
    try { localStorage.setItem('maisonnee:items', JSON.stringify(items)); } catch {}
  }, [items]);

  // ── Persistance ──────────────────────────────────────

  const persist = async (it) => {
    pendingRef.current.add(it.id);
    try {
      await apiCall('/items.php', { method: 'POST', body: JSON.stringify(it) });
      setSyncError(null);
    } catch (e) {
      setSyncError(e.message);
    } finally {
      pendingRef.current.delete(it.id);
    }
  };

  const persistDelete = async (id) => {
    try {
      await apiCall('/items.php?id=' + encodeURIComponent(id), { method: 'DELETE' });
      setSyncError(null);
    } catch (e) {
      setSyncError(e.message);
    }
  };

  // ── Actions (persist appelé HORS du setState) ────────

  const upsert = (item) => {
    let merged;
    setItems(prev => {
      const i = prev.findIndex(x => x.id === item.id);
      merged = i === -1 ? { overrides: {}, ...item } : { ...prev[i], ...item };
      return i === -1 ? [...prev, merged] : prev.map(x => x.id === item.id ? merged : x);
    });
    if (merged) persist(merged);
  };

  const remove = (id) => {
    setItems(prev => prev.filter(x => x.id !== id));
    persistDelete(id);
  };

  const setStatusOn = (id, dateStr, status) => {
    let updated;
    setItems(prev => prev.map(x => {
      if (x.id !== id) return x;
      if ((x.recurrence?.kind || 'none') === 'none') {
        if (status === 'not_today') updated = { ...x, date: ymd(addDays(fromYmd(x.date), 1)) };
        else updated = { ...x, status };
      } else {
        if (status === 'not_today') {
          const next = ymd(addDays(fromYmd(dateStr), 1));
          updated = {
            ...x,
            overrides: { ...(x.overrides || {}), [dateStr]: 'cancelled' },
            extraDays: Array.from(new Set([...(x.extraDays || []), next])),
          };
        } else {
          updated = { ...x, overrides: { ...(x.overrides || {}), [dateStr]: status } };
        }
      }
      return updated || x;
    }));
    if (updated) persist(updated);
  };

  return { items, upsert, remove, setStatusOn, synced, syncError, reload: loadItems };
}

Object.assign(window, { useAuthSB, useStoreSB });
