const AUTH_TOKEN_KEY = 'ligbox_ops_token';
const AUTH_USER_KEY = 'ligbox_ops_user';

function getToken() {
  return sessionStorage.getItem(AUTH_TOKEN_KEY);
}

function getUser() {
  try {
    return JSON.parse(sessionStorage.getItem(AUTH_USER_KEY) || 'null');
  } catch {
    return null;
  }
}

function setSession(token, user) {
  sessionStorage.setItem(AUTH_TOKEN_KEY, token);
  sessionStorage.setItem(AUTH_USER_KEY, JSON.stringify(user));
}

function clearSession() {
  sessionStorage.removeItem(AUTH_TOKEN_KEY);
  sessionStorage.removeItem(AUTH_USER_KEY);
}

function isLoggedIn() {
  return Boolean(getToken());
}

function authHeaders(extra = {}) {
  const token = getToken();
  const headers = { ...extra };
  if (token) headers.Authorization = `Bearer ${token}`;
  return headers;
}

const FETCH_TIMEOUT_MS = 12000;

function fetchWithTimeout(url, options = {}, timeoutMs = FETCH_TIMEOUT_MS) {
  const controller = new AbortController();
  const timer = setTimeout(() => controller.abort(), timeoutMs);
  return fetch(url, { ...options, signal: controller.signal }).finally(() => clearTimeout(timer));
}

function requireAuth() {
  if (!isLoggedIn()) {
    window.location.href = '/login.html';
    return false;
  }
  return true;
}

/** Valida JWT no servidor; limpa sessão se expirado/inválido (ex.: após rotação JWT). */
async function ensureValidSession() {
  const token = getToken();
  if (!token) return false;
  try {
    const res = await fetchWithTimeout('/api/v1/auth/me', { headers: authHeaders() });
    if (!res.ok) {
      clearSession();
      return false;
    }
    const me = await res.json();
    setSession(token, {
      username: me.username,
      role: me.role,
      display_name: me.display_name,
    });
    return true;
  } catch (err) {
    console.warn('ensureValidSession:', err?.name || err);
    clearSession();
    return false;
  }
}

function logout() {
  clearSession();
  window.location.replace('/login.html?logout=1');
}

function hasRole(...roles) {
  const user = getUser();
  return user && roles.includes(user.role);
}

function canPatchTickets() {
  return hasRole('super_admin', 'ops_lead', 'technician');
}

function canRunAudit() {
  return hasRole('super_admin', 'ops_lead');
}

function canManageUsers() {
  return hasRole('super_admin');
}

function canManageVm112Domains() {
  return hasRole('super_admin', 'ops_lead');
}

function canAssist() {
  return hasRole('super_admin', 'ops_lead', 'technician');
}

function canReadLeads() {
  return hasRole('super_admin', 'ops_lead', 'technician');
}

function canReadTickets() {
  return hasRole('super_admin', 'ops_lead', 'technician', 'noc');
}

async function login(username, password) {
  const res = await fetchWithTimeout('/api/v1/auth/login', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ username, password }),
  });
  const data = await res.json().catch(() => ({}));
  if (!res.ok) {
    throw new Error(data.detail || `Login falhou (${res.status})`);
  }
  if (data.mfa_required) {
    return { mfaRequired: true, mfaToken: data.mfa_token, username: data.username };
  }
  setSession(data.access_token, {
    username: data.username,
    role: data.role,
    display_name: data.display_name,
  });
  return data;
}

async function loginMfa(mfaToken, totpCode, backupCode) {
  const payload = { mfa_token: mfaToken };
  if (backupCode) payload.backup_code = backupCode;
  else payload.totp_code = totpCode;
  const res = await fetchWithTimeout('/api/v1/auth/login/mfa', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(payload),
  });
  const data = await res.json().catch(() => ({}));
  if (!res.ok) {
    throw new Error(data.detail || `Código 2FA inválido (${res.status})`);
  }
  setSession(data.access_token, {
    username: data.username,
    role: data.role,
    display_name: data.display_name,
  });
  return data;
}

async function mfaRecoverySendEmail(mfaToken) {
  const res = await fetchWithTimeout('/api/v1/auth/mfa-recovery/send-email', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ mfa_token: mfaToken }),
  });
  const data = await res.json().catch(() => ({}));
  if (!res.ok) throw new Error(data.detail || `Falha ao enviar (${res.status})`);
  return data;
}

async function mfaRecoveryVerifyEmail(mfaToken, emailOtp) {
  const res = await fetchWithTimeout('/api/v1/auth/mfa-recovery/verify-email', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ mfa_token: mfaToken, email_otp: emailOtp }),
  });
  const data = await res.json().catch(() => ({}));
  if (!res.ok) throw new Error(data.detail || `Verificação falhou (${res.status})`);
  return data;
}

async function mfaRecoveryComplete(recoveryToken, totpCode) {
  const res = await fetchWithTimeout('/api/v1/auth/mfa-recovery/complete', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ recovery_token: recoveryToken, totp_code: totpCode }),
  });
  const data = await res.json().catch(() => ({}));
  if (!res.ok) throw new Error(data.detail || `Recuperação falhou (${res.status})`);
  if (data.access_token) {
    setSession(data.access_token, {
      username: data.username,
      role: data.role,
      display_name: data.display_name,
    });
  }
  return data;
}
