import { useState, useEffect, useCallback, useRef } from 'react';

function useFetch(url, options = {}) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);
  const abortControllerRef = useRef(null);

  const {
    method = 'GET',
    headers = {},
    body = null,
    skip = false, // Don't auto-fetch on mount
    ...restOptions
  } = options;

  const fetchData = useCallback(async (dynamicBody = null, dynamicOptions = {}) => {
    setLoading(true);
    setError(null);

    // Cancel previous request
    if (abortControllerRef.current) {
      abortControllerRef.current.abort();
    }

    abortControllerRef.current = new AbortController();

    try {
      const finalBody = dynamicBody || body;
      const finalMethod = dynamicOptions.method || method;

      const config = {
        method: finalMethod,
        headers: {
          'Content-Type': 'application/json',
          ...headers,
          ...dynamicOptions.headers
        },
        signal: abortControllerRef.current.signal,
        ...restOptions,
        ...dynamicOptions
      };

      // Add body for POST, PUT, PATCH, DELETE (if needed)
      if (finalBody && ['POST', 'PUT', 'PATCH', 'DELETE'].includes(finalMethod)) {
        config.body = typeof finalBody === 'string' 
          ? finalBody 
          : JSON.stringify(finalBody);
      }

      const response = await fetch(url, config);

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

      // Handle empty responses (like 204 No Content)
      const contentType = response.headers.get('content-type');
      let result = null;

      if (contentType && contentType.includes('application/json')) {
        result = await response.json();
      } else if (response.status !== 204) {
        result = await response.text();
      }

      setData(result);
      setError(null);
      return result;
    } catch (err) {
      if (err.name === 'AbortError') {
        console.log('Fetch aborted');
      } else {
        setError(err.message);
        throw err;
      }
    } finally {
      setLoading(false);
    }
  }, [url, method, body, JSON.stringify(headers), JSON.stringify(restOptions)]);

  useEffect(() => {
    if (!skip && method === 'GET') {
      fetchData();
    }

    return () => {
      if (abortControllerRef.current) {
        abortControllerRef.current.abort();
      }
    };
  }, [fetchData, skip, method]);

  const refetch = useCallback(() => {
    return fetchData();
  }, [fetchData]);

  return { 
    data, 
    loading, 
    error, 
    refetch,
    execute: fetchData // Alias for manual calls
  };
}

export default useFetch;