/**
 * Client-side authentication utilities for handling JWT tokens
 * and automatic refresh
 */

interface AuthTokens {
  accessToken: string;
  refreshToken: string;
}

interface User {
  id: string;
  email: string;
  name: string;
  role: string;
  tier?: string;
}

/**
 * Check if the access token is expired (or will expire within buffer time)
 */
function isTokenExpired(token: string, bufferSeconds: number = 60): boolean {
  try {
    const payload = JSON.parse(atob(token.split('.')[1]));
    const now = Math.floor(Date.now() / 1000);
    return payload.exp <= now + bufferSeconds;
  } catch {
    return true; // Treat invalid tokens as expired
  }
}

/**
 * Store tokens in cookies (server-side should set HttpOnly cookies)
 * This is for client-side access only
 */
export function setTokens(tokens: AuthTokens): void {
  // Note: In production, tokens should be HttpOnly cookies set by server
  // This is for development/testing purposes only
  if (typeof window !== 'undefined') {
    document.cookie = `scriba.access_token=${tokens.accessToken}; path=/; max-age=600; SameSite=Lax`;
    document.cookie = `scriba.refresh_token=${tokens.refreshToken}; path=/; max-age=1209600; SameSite=Lax`;
  }
}

/**
 * Clear all auth tokens
 */
export function clearTokens(): void {
  if (typeof window !== 'undefined') {
    document.cookie = 'scriba.access_token=; path=/; max-age=0; SameSite=Lax';
    document.cookie = 'scriba.refresh_token=; path=/; max-age=0; SameSite=Lax';
    document.cookie = 'scriba.session=; path=/; max-age=0; SameSite=Lax';
  }
}

/**
 * Get the current access token
 */
export function getAccessToken(): string | null {
  if (typeof window === 'undefined') return null;
  
  const match = document.cookie.match(/(^|;) ?scriba\.access_token=([^;]*)(;|$)/);
  return match ? match[2] : null;
}

/**
 * Get the current refresh token
 */
export function getRefreshToken(): string | null {
  if (typeof window === 'undefined') return null;
  
  const match = document.cookie.match(/(^|;) ?scriba\.refresh_token=([^;]*)(;|$)/);
  return match ? match[2] : null;
}

/**
 * Refresh the access token using the refresh token
 */
export async function refreshAccessToken(): Promise<boolean> {
  const refreshToken = getRefreshToken();
  if (!refreshToken) return false;

  try {
    const response = await fetch('/api/auth/refresh', {
      method: 'POST',
      credentials: 'include', // Important: include cookies
    });

    if (response.ok) {
      return true;
    } else {
      // Refresh failed, clear tokens
      clearTokens();
      return false;
    }
  } catch (error) {
    console.error('Token refresh failed:', error);
    clearTokens();
    return false;
  }
}

/**
 * Make an authenticated API request with automatic token refresh
 */
export async function authenticatedFetch(
  url: string,
  options: RequestInit = {}
): Promise<Response> {
  // Check if access token needs refresh
  const accessToken = getAccessToken();
  if (accessToken && isTokenExpired(accessToken)) {
    const refreshed = await refreshAccessToken();
    if (!refreshed) {
      throw new Error('Authentication failed');
    }
  }

  // Make the request with credentials
  const response = await fetch(url, {
    ...options,
    credentials: 'include',
    headers: {
      ...options.headers,
    },
  });

  // If we get a 401, try to refresh and retry once
  if (response.status === 401) {
    const refreshed = await refreshAccessToken();
    if (refreshed) {
      // Retry the request
      return fetch(url, {
        ...options,
        credentials: 'include',
        headers: {
          ...options.headers,
        },
      });
    } else {
      throw new Error('Authentication failed');
    }
  }

  return response;
}

/**
 * Get current user session
 */
export async function getCurrentSession(): Promise<{ user: User } | null> {
  try {
    const response = await authenticatedFetch('/api/auth/session');
    if (response.ok) {
      const data = await response.json();
      return data.authenticated ? data : null;
    }
    return null;
  } catch (error) {
    console.error('Failed to get current session:', error);
    return null;
  }
}

/**
 * Sign in user
 */
export async function signIn(email: string, password: string): Promise<{ user: User } | null> {
  try {
    const response = await fetch('/api/auth/signin', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      credentials: 'include',
      body: JSON.stringify({ email, password }),
    });

    if (response.ok) {
      const data = await response.json();
      return data.success ? data : null;
    } else {
      const error = await response.json();
      throw new Error(error.error || 'Sign in failed');
    }
  } catch (error) {
    console.error('Sign in failed:', error);
    throw error;
  }
}

/**
 * Sign out user
 */
export async function signOut(): Promise<void> {
  try {
    await fetch('/api/auth/signout', {
      method: 'POST',
      credentials: 'include',
    });
  } catch (error) {
    console.error('Sign out error:', error);
  } finally {
    clearTokens();
  }
}

/**
 * Revoke a specific session
 */
export async function revokeSession(sessionId: string, revokeFamily: boolean = false): Promise<void> {
  try {
    const response = await authenticatedFetch('/api/user/sessions/revoke', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ sessionId, revokeFamily }),
    });

    if (!response.ok) {
      throw new Error('Failed to revoke session');
    }
  } catch (error) {
    console.error('Session revocation failed:', error);
    throw error;
  }
}

/**
 * Revoke all user sessions except current
 */
export async function revokeAllSessions(): Promise<void> {
  try {
    const response = await authenticatedFetch('/api/user/sessions/revoke', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ revokeAll: true }),
    });

    if (!response.ok) {
      throw new Error('Failed to revoke all sessions');
    }
  } catch (error) {
    console.error('Session revocation failed:', error);
    throw error;
  }
}

/**
 * Get all user sessions
 */
export async function getUserSessions(): Promise<any[]> {
  try {
    const response = await authenticatedFetch('/api/user/sessions/revoke');
    if (response.ok) {
      const data = await response.json();
      return data.sessions || [];
    }
    return [];
  } catch (error) {
    console.error('Failed to get user sessions:', error);
    return [];
  }
}
