import { API_URL } from "@/config";

// Track in-flight refresh to avoid duplicate requests
let refreshPromise: Promise<boolean> | null = null;
let lastRefreshTime: number = 0;
const REFRESH_COOLDOWN: number = 2000; // 2 second cooldown between refreshes

export interface AuthFetchOptions extends RequestInit {
  [key: string]: unknown;
}

// Auth fetch wrapper
export const authFetch = async (
  url: string,
  options: AuthFetchOptions = {},
  retry: boolean = true
): Promise<Response> => {
  const res = await fetch(url, {
    ...options,
    credentials: "include", // cookie goes automatically
  });

  if (res.status === 401 && retry) {
    // attempt refresh (non-blocking if already in progress)
    try {
      const refreshSuccess = await doRefresh();

      if (!refreshSuccess) throw new Error("Refresh failed");

      // Retry original request once after refresh
      return authFetch(url, options, false);
    } catch (err) {
      console.error("Refresh token failed:", err);
      return res;
    }
  }

  return res;
};

// Centralized refresh function that handles deduplication properly
export async function doRefresh(): Promise<boolean> {
  const now = Date.now();
  
  // If a refresh just succeeded recently, assume we're good
  if (now - lastRefreshTime < REFRESH_COOLDOWN && !refreshPromise) {
    return true;
  }

  // Reuse existing refresh promise if one is in flight
  if (!refreshPromise) {
    refreshPromise = (async () => {
      try {
        const refreshRes = await fetch(`${API_URL}/auth/refresh`, {
          method: "POST",
          credentials: "include",
        });
        
        if (refreshRes.ok) {
          lastRefreshTime = Date.now();
          return true;
        }
        return false;
      } catch (err) {
        console.error("Refresh request failed:", err);
        return false;
      }
    })();
    
    // Clear the promise after it resolves
    refreshPromise.finally(() => {
      refreshPromise = null;
    });
  }

  return refreshPromise;
}

// Refresh token function (HttpOnly cookie flow)
export async function refreshAccessToken(cookieHeader: string | null): Promise<Record<string, unknown> | null> {
  try {
    const res = await fetch(`${API_URL}/auth/refresh`, {
      method: "POST",
      headers: {
        cookie: cookieHeader || "", // forward cookies from the request
      },
    });

    if (!res.ok) {
      throw new Error("Failed to refresh token");
    }

    // assume backend responds with new tokens in JSON
    return await res.json();
  } catch (err) {
    console.error("Refresh token failed:", err);
    return null;
  }
}

/**
 * Ensure authentication is valid before making API requests.
 * Makes a lightweight auth check against our own API and refreshes if needed.
 * Returns true if auth is valid, false if user needs to log in.
 */
export async function ensureAuth(): Promise<boolean> {
  try {
    // Try a lightweight request to our own API that requires auth
    // Using HEAD or a simple endpoint to minimize overhead
    const res = await fetch('/api/discord/channels', {
      method: 'GET',
      credentials: 'include',
    });

    if (res.ok) {
      return true;
    }

    if (res.status === 401) {
      // Try to refresh the token using our centralized refresh handler
      const refreshSuccess = await doRefresh();
      
      if (refreshSuccess) {
        // Retry the auth check after refresh
        const retryRes = await fetch('/api/discord/channels', {
          method: 'GET', 
          credentials: 'include',
        });
        return retryRes.ok;
      }
      return false;
    }

    // Other errors (500, etc.) - assume auth is OK but server issue
    return true;
  } catch (err) {
    console.error('Auth check failed:', err);
    // Network error - don't redirect, let the actual API calls handle it
    return true;
  }
}

export function handleLogout(): void {
   document.cookie.split(";").forEach((cookie) => {
    const name = cookie.split("=")[0].trim();
    document.cookie = `${name}=; Max-Age=0; path=/;`;
  });
  window.location.href = "/";
}