// public/assets/auth.js
/* English comments: auth token helpers and login UI */

(function () {
  const LS_REFRESH = 'scmedia_refresh_token';
  const LS_CLIENT = 'scmedia_client_type';
  const ACCESS_COOKIE = 'scmedia_access_token';
  let refreshPromise = null;
  let refreshTimer = null;

  function getAccessToken() {
    const parts = document.cookie.split(';').map((p) => p.trim());
    for (const part of parts) {
      if (!part) continue;
      const idx = part.indexOf('=');
      if (idx === -1) continue;
      const key = part.slice(0, idx);
      if (key === ACCESS_COOKIE) {
        return decodeURIComponent(part.slice(idx + 1));
      }
    }
    return '';
  }

  function getRefreshToken() {
    return localStorage.getItem(LS_REFRESH) || sessionStorage.getItem(LS_REFRESH) || '';
  }

  function getClientType() {
    return localStorage.getItem(LS_CLIENT) || sessionStorage.getItem(LS_CLIENT) || 'web';
  }

  function setTokens(tokens, clientType = 'web', remember = true) {
    const storage = remember ? localStorage : sessionStorage;
    if (tokens?.refresh_token) storage.setItem(LS_REFRESH, tokens.refresh_token);
    storage.setItem(LS_CLIENT, clientType);
    const other = remember ? sessionStorage : localStorage;
    other.removeItem(LS_REFRESH);
    other.removeItem(LS_CLIENT);
    localStorage.removeItem('scmedia_access_token');
    sessionStorage.removeItem('scmedia_access_token');
  }

  function clearTokens() {
    localStorage.removeItem(LS_REFRESH);
    localStorage.removeItem(LS_CLIENT);
    sessionStorage.removeItem(LS_REFRESH);
    sessionStorage.removeItem(LS_CLIENT);
    localStorage.removeItem('scmedia_access_token');
    sessionStorage.removeItem('scmedia_access_token');
  }

  function parseJwt(token) {
    if (!token) return null;
    const parts = token.split('.');
    if (parts.length !== 3) return null;
    try {
      const payload = JSON.parse(atob(parts[1].replace(/-/g, '+').replace(/_/g, '/')));
      return payload || null;
    } catch (e) {
      return null;
    }
  }

  function getRoles() {
    const payload = parseJwt(getAccessToken());
    return Array.isArray(payload?.roles) ? payload.roles : [];
  }

  function isAccessExpired(leewaySeconds = 30) {
    const payload = parseJwt(getAccessToken());
    const exp = Number(payload?.exp || 0);
    if (!exp) return true;
    const now = Math.floor(Date.now() / 1000);
    return exp <= (now + leewaySeconds);
  }

  function isAdmin() {
    return getRoles().includes('admin');
  }

  function redirectToLogin() {
    if (window.location.pathname !== '/login') {
      window.location.href = '/login';
    }
  }

  function requireAuth() {
    const access = getAccessToken();
    const refresh = getRefreshToken();
    if (!access && !refresh) {
      redirectToLogin();
      return;
    }
    if (!access && refresh) {
      refreshTokens().then((ok) => {
        if (!ok) redirectToLogin();
      });
    }
  }

  async function refreshTokens() {
    if (refreshPromise) return refreshPromise;
    const refresh = getRefreshToken();
    if (!refresh) return false;
    const clientType = getClientType();
    refreshPromise = (async () => {
      const tryRefresh = async (token) => {
        const res = await fetch('/api/auth/refresh', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ refresh_token: token, client_type: clientType }),
        });
        if (!res.ok) return null;
        const data = await res.json();
        if (!data?.ok) return null;
        return data?.data || {};
      };

      let data = await tryRefresh(refresh);
      if (!data) {
        const current = getRefreshToken();
        if (current && current !== refresh) {
          data = await tryRefresh(current);
        }
      }
      if (!data) {
        clearTokens();
        return false;
      }
      setTokens(data, clientType);
      return true;
    })();
    try {
      return await refreshPromise;
    } finally {
      refreshPromise = null;
    }
  }

  async function logout() {
    const refresh = getRefreshToken();
    if (window.UI?.stopSseClient) {
      window.UI.stopSseClient();
    }
    clearTokens();
    try {
      await fetch('/api/auth/logout', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(refresh ? { refresh_token: refresh } : {}),
      });
    } catch (e) {
      // Ignore logout network errors.
    }
    redirectToLogin();
  }

  function initSessionRefresh() {
    if (refreshTimer) {
      clearTimeout(refreshTimer);
      refreshTimer = null;
    }
    const token = getAccessToken();
    const payload = parseJwt(token);
    const exp = Number(payload?.exp || 0);
    if (!exp) return;
    const now = Math.floor(Date.now() / 1000);
    const lead = 45;
    const delayMs = Math.max(1000, (exp - now - lead) * 1000);
    refreshTimer = setTimeout(async () => {
      const ok = await refreshTokens();
      if (ok) {
        initSessionRefresh();
        return;
      }
      clearTokens();
      redirectToLogin();
    }, delayMs);
  }

  function initHeaderControls() {
    const logoutBtn = document.getElementById('btnLogout');
    if (logoutBtn) {
      logoutBtn.addEventListener('click', () => {
        logout();
      });
    }
    const adminBtn = document.getElementById('btnAdmin');
    if (adminBtn) {
      adminBtn.classList.toggle('is-hidden', !isAdmin());
    }
    loadHeaderAvatar().catch(() => {});
  }

  async function loadHeaderAvatar() {
    const img = document.getElementById('headerAvatar');
    if (!img) return;
    const token = getAccessToken();
    if (!token) return;
    const res = await fetch('/api/account/avatar', {
      headers: { Authorization: `Bearer ${token}` },
    });
    if (!res.ok) return;
    const blob = await res.blob();
    const url = URL.createObjectURL(blob);
    img.onload = () => URL.revokeObjectURL(url);
    img.src = url;
  }

  window.Auth = {
    getAccessToken,
    getRefreshToken,
    setTokens,
    clearTokens,
    parseJwt,
    getRoles,
    isAdmin,
    isAccessExpired,
    requireAuth,
    refreshTokens,
    logout,
    redirectToLogin,
    initHeaderControls,
    initSessionRefresh,
  };
})();
