// Short-term failure cache for API auth timeouts
let lastAuthFailureTime: number = 0;
const AUTH_FAILURE_CACHE_MS: number = 30000; // 30 seconds
/**
 * API route authentication helper
 * Validates user session for protected API endpoints
 */
import { API_URL } from '@/config';

export interface User {
  id?: string;
  username?: string;
  roles?: string[];
  [key: string]: unknown;
}

export interface AuthResult {
  user: User | null;
  error: Response | null;
  setCookieHeader: string | string[] | null;
}

/**
 * Check if the request has a valid authentication session
 * @param request - The incoming request
 * @returns Promise with user object, error response, or set-cookie header
 */
export async function requireApiAuth(request: Request): Promise<AuthResult> {
    // If we recently failed due to API timeout, immediately fail closed
    if (Date.now() - lastAuthFailureTime < AUTH_FAILURE_CACHE_MS) {
      return {
        user: null,
        error: new Response(JSON.stringify({ error: 'Authentication error', message: 'API unreachable or timed out (cached)' }), {
          status: 503,
          headers: { 'Content-Type': 'application/json' },
        }),
        setCookieHeader: null,
      };
    }
  try {
    const cookieHeader = request.headers.get('cookie') ?? '';
    
    if (!cookieHeader) {
      return {
        user: null,
        error: new Response(JSON.stringify({ error: 'Authentication required' }), {
          status: 401,
          headers: { 'Content-Type': 'application/json' },
        }),
        setCookieHeader: null,
      };
    }

    // Try to get user identity
    // Add timeout to fetch
    let controller = new AbortController();
    let timeout = setTimeout(() => controller.abort(), 3000); // 3s timeout
    let res;
    try {
      res = await fetch(`${API_URL}/auth/id`, {
        headers: { Cookie: cookieHeader },
        credentials: 'include',
        signal: controller.signal,
      });
    } catch (err) {
      clearTimeout(timeout);
      lastAuthFailureTime = Date.now();
      return {
        user: null,
        error: new Response(JSON.stringify({ error: 'Authentication error', message: 'API unreachable or timed out' }), {
          status: 503,
          headers: { 'Content-Type': 'application/json' },
        }),
        setCookieHeader: null,
      };
    }
    clearTimeout(timeout);

    let newSetCookieHeader: string[] | null = null;

    // If unauthorized, try to refresh the token
    if (res.status === 401) {
      // Add timeout to refresh fetch
      controller = new AbortController();
      timeout = setTimeout(() => controller.abort(), 3000);
      let refreshRes;
      try {
        refreshRes = await fetch(`${API_URL}/auth/refresh`, {
          method: 'POST',
          headers: { Cookie: cookieHeader },
          credentials: 'include',
          signal: controller.signal,
        });
      } catch (err) {
        clearTimeout(timeout);
        return {
          user: null,
          error: new Response(JSON.stringify({ error: 'Authentication error', message: 'API unreachable or timed out' }), {
            status: 503,
            headers: { 'Content-Type': 'application/json' },
          }),
          setCookieHeader: null,
        };
      }
      clearTimeout(timeout);

      if (!refreshRes.ok) {
        return {
          user: null,
          error: new Response(JSON.stringify({ error: 'Session expired' }), {
            status: 401,
            headers: { 'Content-Type': 'application/json' },
          }),
          setCookieHeader: null,
        };
      }

      // Capture the Set-Cookie headers from the refresh response to forward to client
      if (typeof refreshRes.headers.getSetCookie === 'function') {
        newSetCookieHeader = refreshRes.headers.getSetCookie();
      } else {
        const sc = refreshRes.headers.get('set-cookie');
        if (sc) newSetCookieHeader = sc.split(/,(?=\s*\w+=)/).map(s => s.trim());
      }

      let newCookieHeader = cookieHeader;

      if (newSetCookieHeader && newSetCookieHeader.length > 0) {
        // newSetCookieHeader is an array of cookie strings; build a cookie header for the retry
        const cookiesArray = Array.isArray(newSetCookieHeader) ? newSetCookieHeader : [newSetCookieHeader];
        newCookieHeader = cookiesArray.map(c => c.split(';')[0]).join('; ');
      } else {
        return {
          user: null,
          error: new Response(JSON.stringify({ error: 'Session refresh failed' }), {
            status: 401,
            headers: { 'Content-Type': 'application/json' },
          }),
          setCookieHeader: null,
        };
      }

      // Add timeout to retry fetch
      let retryController = new AbortController();
      let retryTimeout = setTimeout(() => retryController.abort(), 3000);
      try {
        res = await fetch(`${API_URL}/auth/id`, {
          headers: { Cookie: newCookieHeader },
          credentials: 'include',
          signal: retryController.signal,
        });
      } catch (err) {
        clearTimeout(retryTimeout);
        lastAuthFailureTime = Date.now();
        return {
          user: null,
          error: new Response(JSON.stringify({ error: 'Authentication error', message: 'API unreachable or timed out' }), {
            status: 503,
            headers: { 'Content-Type': 'application/json' },
          }),
          setCookieHeader: null,
        };
      }
      clearTimeout(retryTimeout);
    }

    if (!res.ok) {
      return {
        user: null,
        error: new Response(JSON.stringify({ error: 'Authentication failed' }), {
          status: 401,
          headers: { 'Content-Type': 'application/json' },
        }),
        setCookieHeader: null,
      };
    }

    const user = await res.json();
    return { user, error: null, setCookieHeader: newSetCookieHeader };
  } catch (err) {
    console.error('API auth error:', err);
    return {
      user: null,
      error: new Response(JSON.stringify({ error: 'Authentication error' }), {
        status: 500,
        headers: { 'Content-Type': 'application/json' },
      }),
      setCookieHeader: null,
    };
  }
}

/**
 * Helper to create a response with optional Set-Cookie header forwarding
 * @param data - Response data
 * @param status - HTTP status code  
 * @param setCookieHeader - Set-Cookie header from auth refresh
 */
export function createApiResponse(
  data: unknown,
  status: number = 200,
  setCookieHeader: string | string[] | null = null
): Response {
  const headers = new Headers({ 'Content-Type': 'application/json' });
  if (setCookieHeader) {
    const cookies = Array.isArray(setCookieHeader) ? setCookieHeader : [setCookieHeader];
    for (const c of cookies) {
      if (c) headers.append('Set-Cookie', c.trim());
    }
  }
  return new Response(JSON.stringify(data), { status, headers });
}
