const API_URL = import.meta.env.VITE_EFC_API_URL;

// 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 = [];
};

// Función para renovar el token usando el refresh token
const refreshToken = async () => {
  try {
    const refresh = localStorage.getItem('refresh');
    if (!refresh) {
      throw new Error('No refresh token available');
    }

    // Intentar primero con el endpoint completo
    let refreshEndpoint = `${API_URL}/token/refresh/`;
    
    let response = await fetch(refreshEndpoint, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        refresh: refresh
      }),
    });

    // Si falla con 404, intentar con el endpoint alternativo
    if (response.status === 404) {
      refreshEndpoint = `${API_URL}/token/refresh/`;
      response = await fetch(refreshEndpoint, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          refresh: refresh
        }),
      });
    }

    if (!response.ok) {
      const errorText = await response.text();
      throw new Error(`Failed to refresh token: ${response.status} - ${errorText}`);
    }

    const data = await response.json();
    
    // Guardar el nuevo access token
    localStorage.setItem('access', data.access);
    
    // Si viene un nuevo refresh token, guardarlo también
    if (data.refresh) {
      localStorage.setItem('refresh', data.refresh);
    }

    return data.access;
  } catch (error) {
    // Si falla la renovación, limpiar tokens y redirigir al login
    localStorage.removeItem('access');
    localStorage.removeItem('refresh');
    localStorage.removeItem('user_id');
    localStorage.removeItem('user_is_importador');
    
    // Redirigir al login después de un pequeño delay
    setTimeout(() => {
      window.location.href = '/login';
    }, 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
    }
  };

  try {
    // Hacer la petición inicial
    let response = await fetch(url, finalOptions);

    // Si la respuesta es 401 (Unauthorized), manejar renovación de token
    if (response.status === 401) {
      if (!isRefreshing) {
        isRefreshing = true;

        try {
          // Renovar el token
          const newToken = await refreshToken();
          
          // Procesar la cola de peticiones pendientes
          processQueue(null, newToken);
          
          // Actualizar el header de autorización y reintentar la petición original
          finalOptions.headers['Authorization'] = `Bearer ${newToken}`;
          response = await fetch(url, finalOptions);
          
        } catch (refreshError) {
          // Si falla la renovación, procesar la cola con error
          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) => {
              finalOptions.headers['Authorization'] = `Bearer ${token}`;
              fetch(url, finalOptions)
                .then(resolve)
                .catch(reject);
            },
            reject
          });
        });
      }
    }
    
    // Si todavía hay un 401 después del intento de renovación, verificar si realmente es un problema de auth
    if (response.status === 401) {
      // Verificar si tenemos un token válido en localStorage
      const currentToken = localStorage.getItem('access');
      
      // Intentar obtener más información del error
      let errorDetails = '';
      try {
        const errorText = await response.text();
        errorDetails = errorText;
      } catch (e) {
        // Error al leer respuesta
      }
      
      // Si no hay token o el error indica problema de autenticación, limpiar sesión
      if (!currentToken || errorDetails.includes('token') || errorDetails.includes('auth')) {
        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');
      } else {
        // Si hay token pero sigue fallando, podría ser un problema del servidor
        // No limpiar la sesión, dejar que el error se propague
      }
    }

    return response;

  } catch (error) {
    // Si hay un error de red o cualquier otro error, propagarlo
    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;
