/**
 * BetterAuth client for frontend authentication.
 *
 * This client handles:
 * - Sign in/out operations
 * - Session management
 * - Cookie-based session lifecycle
 */
import { createAuthClient } from "better-auth/react";
import { genericOAuthClient } from "better-auth/client/plugins";
import { API_BASE_URL } from "./config";
import { parseAuthError } from "./auth/auth-errors";

/**
 * Auth client instance configured for Mosaic Stack.
 */
export const authClient = createAuthClient({
  baseURL: API_BASE_URL,
  basePath: "/auth",
  plugins: [genericOAuthClient()],
});

/**
 * Export commonly used auth functions.
 */
export const { signIn, signOut, useSession, getSession } = authClient;

/**
 * Sign in with email and password.
 * Returns the session on success, throws on failure.
 *
 * Uses direct fetch to POST credentials to BetterAuth's sign-in endpoint.
 * The email parameter accepts an email address used as the credential identifier.
 */
export async function signInWithCredentials(email: string, password: string): Promise<unknown> {
  const response = await fetch(`${API_BASE_URL}/auth/sign-in/credentials`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    credentials: "include", // Include cookies
    body: JSON.stringify({ email, password }),
  });

  if (!response.ok) {
    let errorBody: { message?: string } = {};
    try {
      errorBody = (await response.json()) as { message?: string };
    } catch (jsonError: unknown) {
      console.error(
        `[Auth] Failed to parse error response body (HTTP ${String(response.status)}):`,
        jsonError
      );
    }
    const parsed = parseAuthError(errorBody.message ? new Error(errorBody.message) : response);
    throw new Error(parsed.message);
  }

  const data = (await response.json()) as unknown;
  return data;
}

/**
 * Get the current access token for API calls.
 * Returns null if not authenticated.
 */
export async function getAccessToken(): Promise<string | null> {
  try {
    const session = await getSession();
    if (!session.data?.user) {
      return null;
    }

    // Type assertion for custom user fields
    const user = session.data.user as {
      accessToken?: string;
      tokenExpiresAt?: number;
    };

    if (!user.accessToken) {
      console.warn("[Auth] Session exists but no accessToken found");
      return null;
    }

    // Check if token is expired (with 1 minute buffer)
    if (user.tokenExpiresAt && user.tokenExpiresAt - Date.now() < 60000) {
      // Token is expired or about to expire
      // The session will be refreshed automatically by BetterAuth
      // but we should return null to trigger a re-auth if needed
      return null;
    }

    return user.accessToken;
  } catch (error: unknown) {
    console.error("[Auth] Failed to get access token:", error);
    return null;
  }
}

/**
 * Check if the current user is an admin.
 */
export async function isAdmin(): Promise<boolean> {
  try {
    const session = await getSession();
    if (!session.data?.user) {
      return false;
    }

    const user = session.data.user as { isAdmin?: boolean };
    return user.isAdmin === true;
  } catch (error: unknown) {
    console.error("[Auth] Failed to check admin status:", error);
    return false;
  }
}
