import { useCallback, useEffect, useRef, useState } from 'react';
import { getCachedData, setCachedData } from '../services/cache';

interface CachedQueryResult<T> {
  data: T | null;
  isLoading: boolean;
  isFromCache: boolean;
  error: Error | null;
  refetch: () => Promise<void>;
}

/**
 * Hook that wraps a data-fetching function with offline-first cache logic.
 *
 * 1. On mount: try cache first, then fetch from API and update cache.
 * 2. If the API fails and cache exists, return cached data with `isFromCache = true`.
 * 3. If offline (network error), return cached data and set `isFromCache = true`.
 */
export function useCachedQuery<T = any>(
  cacheKey: string,
  fetchFn: () => Promise<T>,
  ttlSeconds: number,
): CachedQueryResult<T> {
  const [data, setData] = useState<T | null>(null);
  const [isLoading, setIsLoading] = useState<boolean>(true);
  const [isFromCache, setIsFromCache] = useState<boolean>(false);
  const [error, setError] = useState<Error | null>(null);
  const isMounted = useRef(true);

  const fetch = useCallback(async () => {
    setIsLoading(true);
    setError(null);
    setIsFromCache(false);

    let servedFromCache = false;

    // 1. Try cache first
    try {
      const cached = await getCachedData<T>(cacheKey, ttlSeconds);
      if (cached !== null) {
        if (isMounted.current) {
          setData(cached);
          setIsFromCache(true);
          setIsLoading(false);
        }
        servedFromCache = true;
      }
    } catch {
      // Cache read failed — proceed to network
    }

    // 2. Fetch from API
    try {
      const fresh = await fetchFn();
      if (isMounted.current) {
        setData(fresh);
        setIsFromCache(false);
        setError(null);
      }
      // 3. Update cache in background
      setCachedData(cacheKey, fresh, ttlSeconds).catch(() => {});
    } catch (err: any) {
      // If we already served cached data, keep it
      if (servedFromCache) {
        if (isMounted.current) {
          // Keep existing data, just clear loading
          setIsLoading(false);
        }
        return;
      }

      // API failed and no cache — surface the error
      if (isMounted.current) {
        setError(err instanceof Error ? err : new Error(String(err)));
        setIsLoading(false);
      }
    } finally {
      if (!servedFromCache && isMounted.current) {
        setIsLoading(false);
      }
    }
  }, [cacheKey, fetchFn, ttlSeconds]);

  useEffect(() => {
    isMounted.current = true;
    fetch();
    return () => {
      isMounted.current = false;
    };
  }, [fetch]);

  return { data, isLoading, isFromCache, error, refetch: fetch };
}
