const API_BASE_URL = import.meta.env.VITE_API_BASE_URL;
let reloginInProgress = false;

function redirectToLogin() {
  // Always clean up body-level modals regardless of current hash —
  // auth:logout can navigate to #login before this runs, making the hash check a no-op.
  document.querySelectorAll('body > [class*="overlay"], body > [class*="modal"]').forEach(el => {
    if (!el.classList.contains('connection-lost-overlay')) el.remove();
  });
  if (window.location.hash !== '#login') {
    window.location.hash = '#login';
  }
}

function showConnectionLostNotice(message) {
  if (!document?.body) {
    alert(message);
    redirectToLogin();
    return;
  }

  const existing = document.querySelector('.connection-lost-overlay');
  if (existing) {
    return;
  }

  const overlay = document.createElement('div');
  overlay.className = 'connection-lost-overlay';
  overlay.innerHTML = `
    <div class="connection-lost-modal" role="alertdialog" aria-modal="true" aria-labelledby="connection-lost-title">
      <h3 id="connection-lost-title">Conexion perdida</h3>
      <p>${message}</p>
      <p class="connection-lost-sub">Seras redirigido al login en <strong id="connection-lost-countdown">3</strong> segundos.</p>
      <button type="button" class="connection-lost-login-btn">Ir al login ahora</button>
    </div>
  `;

  const countdownEl = overlay.querySelector('#connection-lost-countdown');
  const loginNowBtn = overlay.querySelector('.connection-lost-login-btn');
  let seconds = 3;

  const finishRedirect = () => {
    clearInterval(timerId);
    overlay.remove();
    redirectToLogin();
  };

  const timerId = setInterval(() => {
    seconds -= 1;
    if (countdownEl) {
      countdownEl.textContent = String(Math.max(0, seconds));
    }

    if (seconds <= 0) {
      finishRedirect();
    }
  }, 1000);

  loginNowBtn?.addEventListener('click', finishRedirect);
  document.body.appendChild(overlay);
}

function forceRelogin(message) {
  if (reloginInProgress) {
    return;
  }
  reloginInProgress = true;

  localStorage.removeItem('user');
  localStorage.removeItem('token');
  sessionStorage.setItem('session-expired-message', message);
  window.dispatchEvent(new Event('auth:logout'));

  showConnectionLostNotice(message);
}

function buildUrl(path) {
  if (path.startsWith('http://') || path.startsWith('https://')) {
    return path;
  }

  return `${API_BASE_URL}${path.startsWith('/') ? '' : '/'}${path}`;
}

function buildHeaders({ auth = true, headers = {}, hasJsonBody = false }) {
  const finalHeaders = { ...headers };

  if (auth) {
    const token = localStorage.getItem('token');
    if (token) {
      finalHeaders.Authorization = `Bearer ${token}`;
    }
  }

  if (hasJsonBody && !finalHeaders['Content-Type']) {
    finalHeaders['Content-Type'] = 'application/json';
  }

  return finalHeaders;
}

async function parseError(response) {
  const contentType = response.headers.get('content-type') || '';

  if (contentType.includes('application/json')) {
    const data = await response.json().catch(() => ({}));
    return data.detail || data.message || data.error || `HTTP ${response.status}`;
  }

  const text = await response.text().catch(() => '');
  return text || `HTTP ${response.status}`;
}

export async function apiRequest(path, options = {}) {
  const {
    method = 'GET',
    auth = true,
    headers = {},
    body,
    responseType = 'json'
  } = options;

  const isJsonBody = body !== undefined && body !== null && !(body instanceof FormData);

  let response;
  try {
    response = await fetch(buildUrl(path), {
      method,
      headers: buildHeaders({ auth, headers, hasJsonBody: isJsonBody }),
      body: isJsonBody ? JSON.stringify(body) : body
    });
  } catch (error) {
    if (auth) {
      forceRelogin('Se ha perdido la conexion con el servidor. Debes volver a iniciar sesion.');
    }
    throw new Error('Se ha perdido la conexion con el servidor.');
  }

  if (!response.ok) {
    if (auth && (response.status === 401 || response.status === 403 || response.status === 503)) {
      forceRelogin('Se ha perdido la conexion con el servidor. Debes volver a iniciar sesion.');
    }
    throw new Error(await parseError(response));
  }

  if (responseType === 'raw') {
    return response;
  }

  if (response.status === 204) {
    return null;
  }

  if (responseType === 'blob') {
    return response.blob();
  }

  if (responseType === 'text') {
    return response.text();
  }

  return response.json();
}

export function apiGet(path, options = {}) {
  return apiRequest(path, { ...options, method: 'GET' });
}

export function apiPost(path, body, options = {}) {
  return apiRequest(path, { ...options, method: 'POST', body });
}

export function apiPut(path, body, options = {}) {
  return apiRequest(path, { ...options, method: 'PUT', body });
}

export function apiPatch(path, body, options = {}) {
  return apiRequest(path, { ...options, method: 'PATCH', body });
}

export function apiDelete(path, options = {}) {
  return apiRequest(path, { ...options, method: 'DELETE' });
}