import type { AuthConfig } from "./config";

export type DiscordProfile = {
  id: string;
  username: string;
  global_name: string | null;
  avatar: string | null;
};

export type FetchDiscord = (url: string, init: RequestInit) => Promise<Response>;

export async function fetchDiscordProfile(code: string, config: AuthConfig, request: FetchDiscord): Promise<DiscordProfile> {
  const tokenResponse = await request("https://discord.com/api/oauth2/token", {
    method: "POST",
    headers: { "Content-Type": "application/x-www-form-urlencoded" },
    body: new URLSearchParams({
      grant_type: "authorization_code",
      client_id: config.clientId,
      client_secret: config.clientSecret,
      redirect_uri: `${config.origin}/api/auth/discord/callback`,
      code,
    }),
    signal: AbortSignal.timeout(10_000),
  });
  if (!tokenResponse.ok) throw new Error("Discord token exchange failed");
  const token = await tokenResponse.json();
  if (typeof token.access_token !== "string" || !token.access_token ||
      typeof token.token_type !== "string" || token.token_type.toLowerCase() !== "bearer" ||
      typeof token.scope !== "string" || !token.scope.split(" ").includes("identify")) {
    throw new Error("Invalid Discord token response");
  }
  const profileResponse = await request("https://discord.com/api/v10/users/@me", {
    headers: { Authorization: `Bearer ${token.access_token}` },
    signal: AbortSignal.timeout(10_000),
  });
  if (!profileResponse.ok) throw new Error("Discord profile request failed");
  const profile = await profileResponse.json();
  if (!profile || typeof profile.id !== "string" || !/^\d{1,20}$/.test(profile.id) ||
      typeof profile.username !== "string" || !profile.username ||
      !(profile.global_name === null || typeof profile.global_name === "string") ||
      !(profile.avatar === null || (typeof profile.avatar === "string" && /^(a_)?[a-f0-9]+$/.test(profile.avatar)))) {
    throw new Error("Invalid Discord profile");
  }
  return profile;
}
