const API_URL  = import.meta.env.VITE_EFC_API_URL;               // e.g. http://localhost:8000/api/v1
const BASE_URL = API_URL.replace(/\/api\/v1\/?$/, '');            // e.g. http://localhost:8000

// Variable para controlar si ya hay una renovación de token en proceso
let isRefreshing = false;
let failedQueue = [];

// Función para procesar la cola de peticiones fallidas después de renovar el token
const processQueue = (error, token = null) => {
  failedQueue.forEach(prom => {
    if (error) {
      prom.reject(error);
    } else {
      prom.resolve(token);
    }
  });
  
  failedQueue = [];
};

/**
 * Intenta renovar el token. Estrategia:
 *   1. Nuevo endpoint cookie-based (SSO / hub-frontend): no requiere body,
 *      lee el refresh_token desde la cookie HTTP-only.
 *   2. Fallback legacy (apps antiguas): lee refresh de localStorage y llama
 *      al endpoint de SimpleJWT.
 */
const refreshToken = async () => {
  // ── Intento 1: SimpleJWT refresh (login directo EFC) ──────────────────
  // Usa el endpoint estándar de SimpleJWT con el token de localStorage.
  const refresh = localStorage.getItem('refresh');
  if (refresh) {
    try {
      // Endpoint SimpleJWT estándar (login EFC directo) — campo "refresh"
      const res = await fetch(`${BASE_URL}/api/v1/token/refresh/`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ refresh }),
      });
      if (res.ok) {
        const data = await res.json();
        const newAccess = data.access;
        if (newAccess) {
          localStorage.setItem('access', newAccess);
          if (data.refresh) localStorage.setItem('refresh', data.refresh);
          return newAccess;
        }
      }
    } catch (_) {
      // continúa al fallback
    }

    try {
      // Fallback: endpoint SSO local (tokens HS256 de sesiones Hub)
      const res = await fetch(`${API_URL}/auth/session/refresh/`, {
        method: 'POST',
        credentials: 'include',
      });
      if (res.ok) {
        const data = await res.json();
        const newAccess = data.access_token || data.access;
        if (newAccess) {
          localStorage.setItem('access', newAccess);
          return newAccess;
        }
      }
    } catch (_) {}
  }

  // ── Fallo total: limpiar sesión y redirigir al Hub ─────────────────────
  localStorage.removeItem('access');
  localStorage.removeItem('refresh');
  localStorage.removeItem('user_id');
  localStorage.removeItem('user_is_importador');
  localStorage.removeItem('user_permissions');

  const hubUrl = import.meta.env.VITE_HUB_URL || 'http://localhost:3001';
  const returnTo = encodeURIComponent(`${window.location.origin}/auth/sso`);
  setTimeout(() => {
    window.location.href = `${hubUrl}/login?return_to=${returnTo}`;
  }, 1000);

  throw new Error('SESSION_EXPIRED');
};

// Función principal para hacer peticiones con manejo automático de tokens
export const fetchWithAuth = async (url, options = {}) => {

  // Obtener el token actual
  let token = localStorage.getItem('access');

  // Configurar headers por defecto
  let defaultHeaders = {};
  if (token) defaultHeaders['Authorization'] = `Bearer ${token}`;
  // Solo poner Content-Type si no es GET o si hay body
  if ((options.method && options.method.toUpperCase() !== 'GET') || options.body) {
    defaultHeaders['Content-Type'] = 'application/json';
  }

  // Combinar headers
  const finalOptions = {
    ...options,
    headers: {
      ...defaultHeaders,
      ...options.headers
    }
  };

  // Helper: ejecutar fetch con reintento ante error de red (Fix E)
  const safeFetch = async (u, opts, retries = 1) => {
    for (let i = 0; i <= retries; i++) {
      try {
        return await fetch(u, opts);
      } catch (networkErr) {
        if (i === retries) throw networkErr;
        await new Promise(r => setTimeout(r, 300 * (i + 1))); // backoff 300ms
      }
    }
  };

  try {
    let response = await safeFetch(url, finalOptions);

    // 401 → intentar renovar token
    if (response.status === 401) {
      if (!isRefreshing) {
        isRefreshing = true;
        try {
          const newToken = await refreshToken();
          processQueue(null, newToken);
          finalOptions.headers['Authorization'] = `Bearer ${newToken}`;
          response = await safeFetch(url, finalOptions);
        } catch (refreshError) {
          processQueue(refreshError, null);
          throw refreshError;
        } finally {
          isRefreshing = false;
        }
      } else {
        // Otro refresh en curso — encolar y esperar
        return new Promise((resolve, reject) => {
          failedQueue.push({
            resolve: (tok) => {
              finalOptions.headers['Authorization'] = `Bearer ${tok}`;
              safeFetch(url, finalOptions).then(resolve).catch(reject);
            },
            reject,
          });
        });
      }
    }

    // 401 persistente después del retry → la sesión expiró definitivamente
    if (response.status === 401) {
      localStorage.removeItem('access');
      localStorage.removeItem('refresh');
      localStorage.removeItem('user_id');
      localStorage.removeItem('user_is_importador');
      localStorage.removeItem('user_permissions');
      const hubUrl = import.meta.env.VITE_HUB_URL || 'http://localhost:3001';
      const returnTo = encodeURIComponent(`${window.location.origin}/auth/sso`);
      setTimeout(() => { window.location.href = `${hubUrl}/login?return_to=${returnTo}`; }, 800);
      throw new Error('SESSION_EXPIRED');
    }

    return response;

  } catch (error) {
    throw error;
  }
};

// Función auxiliar para hacer peticiones GET con manejo de tokens
export const getWithAuth = async (url) => {
  return fetchWithAuth(url, { method: 'GET' });
};

// Función auxiliar para hacer peticiones POST con manejo de tokens
export const postWithAuth = async (url, data) => {
  return fetchWithAuth(url, {
    method: 'POST',
    body: JSON.stringify(data)
  });
};

// Función auxiliar para hacer peticiones PUT con manejo de tokens
export const putWithAuth = async (url, data) => {
  return fetchWithAuth(url, {
    method: 'PUT',
    body: JSON.stringify(data)
  });
};

// Función auxiliar para hacer peticiones PATCH con manejo de tokens
export const patchWithAuth = async (url, data) => {
  return fetchWithAuth(url, {
    method: 'PATCH',
    body: JSON.stringify(data)
  });
};

// Función auxiliar para hacer peticiones DELETE con manejo de tokens
export const deleteWithAuth = async (url) => {
  return fetchWithAuth(url, { method: 'DELETE' });
};

// Función para hacer peticiones con FormData (para archivos)
export const postFormDataWithAuth = async (url, formData) => {
  let token = localStorage.getItem('access');
  
  const options = {
    method: 'POST',
    headers: {
      ...(token && { 'Authorization': `Bearer ${token}` })
    },
    body: formData
  };

  try {
    let response = await fetch(url, options);

    if (response.status === 401) {
      if (!isRefreshing) {
        isRefreshing = true;

        try {
          const newToken = await refreshToken();
          processQueue(null, newToken);
          
          options.headers['Authorization'] = `Bearer ${newToken}`;
          response = await fetch(url, options);
          
        } catch (refreshError) {
          processQueue(refreshError, null);
          throw refreshError;
        } finally {
          isRefreshing = false;
        }
      } else {
        // Ya hay un refresh en proceso, agregar esta petición a la cola
        return new Promise((resolve, reject) => {
          failedQueue.push({
            resolve: (token) => {
              options.headers['Authorization'] = `Bearer ${token}`;
              fetch(url, options)
                .then(resolve)
                .catch(reject);
            },
            reject
          });
        });
      }
    }
    
    if (response.status === 401) {
      localStorage.removeItem('access');
      localStorage.removeItem('refresh');
      localStorage.removeItem('user_id');
      localStorage.removeItem('user_is_importador');
      
      setTimeout(() => {
        window.location.href = '/login';
      }, 1000);
      
      throw new Error('Session expired');
    }

    return response;

  } catch (error) {
    throw error;
  }
};

// Función para hacer peticiones PUT con FormData (para archivos)
export const putFormDataWithAuth = async (url, formData) => {
  let token = localStorage.getItem('access');
  
  const options = {
    method: 'PUT',
    headers: {
      ...(token && { 'Authorization': `Bearer ${token}` })
    },
    body: formData
  };

  try {
    let response = await fetch(url, options);

    if (response.status === 401) {
      if (!isRefreshing) {
        isRefreshing = true;

        try {
          const newToken = await refreshToken();
          processQueue(null, newToken);
          
          options.headers['Authorization'] = `Bearer ${newToken}`;
          response = await fetch(url, options);
          
        } catch (refreshError) {
          processQueue(refreshError, null);
          throw refreshError;
        } finally {
          isRefreshing = false;
        }
      } else {
        // Ya hay un refresh en proceso, agregar esta petición a la cola
        return new Promise((resolve, reject) => {
          failedQueue.push({
            resolve: (token) => {
              options.headers['Authorization'] = `Bearer ${token}`;
              fetch(url, options)
                .then(resolve)
                .catch(reject);
            },
            reject
          });
        });
      }
    }
    
    if (response.status === 401) {
      localStorage.removeItem('access');
      localStorage.removeItem('refresh');
      localStorage.removeItem('user_id');
      localStorage.removeItem('user_is_importador');
      
      setTimeout(() => {
        window.location.href = '/login';
      }, 1000);
      
      throw new Error('Session expired');
    }

    return response;

  } catch (error) {
    throw error;
  }
};

// Función para hacer peticiones PATCH con FormData (para archivos)
export const patchFormDataWithAuth = async (url, formData) => {
  let token = localStorage.getItem('access');
  
  const options = {
    method: 'PATCH',
    headers: {
      ...(token && { 'Authorization': `Bearer ${token}` })
    },
    body: formData
  };

  try {
    let response = await fetch(url, options);

    if (response.status === 401) {
      if (!isRefreshing) {
        isRefreshing = true;

        try {
          const newToken = await refreshToken();
          processQueue(null, newToken);
          
          options.headers['Authorization'] = `Bearer ${newToken}`;
          response = await fetch(url, options);
          
        } catch (refreshError) {
          processQueue(refreshError, null);
          throw refreshError;
        } finally {
          isRefreshing = false;
        }
      } else {
        // Ya hay un refresh en proceso, agregar esta petición a la cola
        return new Promise((resolve, reject) => {
          failedQueue.push({
            resolve: (token) => {
              options.headers['Authorization'] = `Bearer ${token}`;
              fetch(url, options)
                .then(resolve)
                .catch(reject);
            },
            reject
          });
        });
      }
    }
    
    if (response.status === 401) {
      localStorage.removeItem('access');
      localStorage.removeItem('refresh');
      localStorage.removeItem('user_id');
      localStorage.removeItem('user_is_importador');
      
      setTimeout(() => {
        window.location.href = '/login';
      }, 1000);
      
      throw new Error('Session expired');
    }

    return response;

  } catch (error) {
    throw error;
  }
};

export default fetchWithAuth;
