// ──────────────────────────────────────────────────────────────────────────────
// GOG (Good Old Games) API service
// Uses GOG OAuth2 for user authentication.  All paginated requests include a
// 500 ms pause between pages to respect rate-limits.
// ──────────────────────────────────────────────────────────────────────────────

const GOG_CLIENT_ID = '46899977096215655';
const GOG_CLIENT_SECRET =
  '9d85c43b1482497dbbce61f6e4aa173a433796eebd2c1f0f7f015c4c2e57571';
const GOG_AUTH_URL = 'https://auth.gog.com/auth';
const GOG_TOKEN_URL = 'https://auth.gog.com/token';
const GOG_EMBED_URL = 'https://embed.gog.com';
const GOG_REDIRECT_URI = 'https://embed.gog.com/on_login_success?origin=client';

// ── Types ────────────────────────────────────────────────────────────────────

export interface GogTokens {
  accessToken: string;
  refreshToken: string;
  expiresAt: number; // unix-ms
  userId: string;
}

export interface GogUserInfo {
  userId: string;
  username: string;
  avatarUrl: string;
}

export interface GogGame {
  gogId: number;
  title: string;
  image: string; // cover URL from GOG
  slug: string;
}

// ── OAuth helpers ────────────────────────────────────────────────────────────

/**
 * Build the GOG OAuth authorization URL that the user should visit to grant
 * access.  After approval, GOG redirects to `embed.gog.com/on_login_success`
 * with a `code` query parameter that the user copies back into the app.
 */
export function getGogAuthUrl(): string {
  const params = new URLSearchParams({
    client_id: GOG_CLIENT_ID,
    redirect_uri: GOG_REDIRECT_URI,
    response_type: 'code',
    layout: 'client2',
  });

  return `${GOG_AUTH_URL}?${params.toString()}`;
}

/**
 * Exchange an authorization code for GOG access + refresh tokens.
 * Uses the fixed GOG_REDIRECT_URI that matches the OAuth registration.
 */
export async function exchangeGogCode(
  code: string,
): Promise<GogTokens> {
  console.log('[GOG] Exchanging authorization code for tokens...');

  const params = new URLSearchParams({
    client_id: GOG_CLIENT_ID,
    client_secret: GOG_CLIENT_SECRET,
    grant_type: 'authorization_code',
    code,
    redirect_uri: GOG_REDIRECT_URI,
  });

  const res = await fetch(`${GOG_TOKEN_URL}?${params.toString()}`);

  if (!res.ok) {
    const text = await res.text();
    console.error(`[GOG] Token exchange failed (${res.status}): ${text}`);
    throw new Error(`[GOG] Token exchange failed (${res.status}): ${text}`);
  }

  const data = (await res.json()) as {
    access_token: string;
    refresh_token: string;
    expires_in: number;
    user_id: string;
    token_type: string;
  };

  const tokens: GogTokens = {
    accessToken: data.access_token,
    refreshToken: data.refresh_token,
    expiresAt: Date.now() + data.expires_in * 1000,
    userId: data.user_id,
  };

  console.log(
    `[GOG] Tokens acquired for user ${tokens.userId}, expires in ${Math.round(data.expires_in / 3600)} hours`,
  );

  return tokens;
}

/**
 * Obtain a fresh set of tokens using an existing refresh token.
 */
export async function refreshGogToken(
  refreshToken: string,
): Promise<GogTokens> {
  console.log('[GOG] Refreshing access token...');

  const params = new URLSearchParams({
    client_id: GOG_CLIENT_ID,
    client_secret: GOG_CLIENT_SECRET,
    grant_type: 'refresh_token',
    refresh_token: refreshToken,
  });

  const res = await fetch(`${GOG_TOKEN_URL}?${params.toString()}`);

  if (!res.ok) {
    const text = await res.text();
    console.error(`[GOG] Token refresh failed (${res.status}): ${text}`);
    throw new Error(`[GOG] Token refresh failed (${res.status}): ${text}`);
  }

  const data = (await res.json()) as {
    access_token: string;
    refresh_token: string;
    expires_in: number;
    user_id: string;
    token_type: string;
  };

  const tokens: GogTokens = {
    accessToken: data.access_token,
    refreshToken: data.refresh_token,
    expiresAt: Date.now() + data.expires_in * 1000,
    userId: data.user_id,
  };

  console.log(
    `[GOG] Token refreshed for user ${tokens.userId}, expires in ${Math.round(data.expires_in / 3600)} hours`,
  );

  return tokens;
}

// ── User info ────────────────────────────────────────────────────────────────

/**
 * Fetch basic user profile information from the GOG embed API.
 */
export async function fetchGogUserInfo(
  accessToken: string,
): Promise<GogUserInfo> {
  console.log('[GOG] Fetching user info...');

  const res = await fetch(`${GOG_EMBED_URL}/userData.json`, {
    headers: {
      Authorization: `Bearer ${accessToken}`,
    },
  });

  if (!res.ok) {
    const text = await res.text();
    console.error(`[GOG] User info request failed (${res.status}): ${text}`);
    throw new Error(`[GOG] User info request failed (${res.status}): ${text}`);
  }

  const data = (await res.json()) as {
    userId: string;
    username: string;
    galaxyUserId: string;
    avatar: string;
  };

  const userInfo: GogUserInfo = {
    userId: data.galaxyUserId || data.userId,
    username: data.username,
    avatarUrl: data.avatar ? `https:${data.avatar}` : '',
  };

  console.log(`[GOG] User info fetched: ${userInfo.username}`);

  return userInfo;
}

// ── Game library ─────────────────────────────────────────────────────────────

/**
 * Fetch the complete list of owned GOG games for the authenticated user.
 *
 * The GOG embed API paginates results (one page at a time).  We iterate
 * through all pages with a 500 ms pause between requests to stay friendly.
 */
export async function fetchGogGames(
  accessToken: string,
): Promise<GogGame[]> {
  console.log('[GOG] Fetching game library...');

  const allGames: GogGame[] = [];
  let currentPage = 1;
  let totalPages = 1;

  do {
    const url = `${GOG_EMBED_URL}/account/getFilteredProducts?mediaType=1&page=${currentPage}`;

    const res = await fetch(url, {
      headers: {
        Authorization: `Bearer ${accessToken}`,
      },
    });

    if (!res.ok) {
      const text = await res.text();
      console.error(
        `[GOG] Game library request failed on page ${currentPage} (${res.status}): ${text}`,
      );
      throw new Error(
        `[GOG] Game library request failed (${res.status}): ${text}`,
      );
    }

    const data = (await res.json()) as {
      totalPages: number;
      products: Array<{
        id: number;
        title: string;
        image: string;
        slug: string;
      }>;
    };

    totalPages = data.totalPages;

    for (const product of data.products) {
      allGames.push({
        gogId: product.id,
        title: product.title,
        image: product.image ? `https:${product.image}` : '',
        slug: product.slug,
      });
    }

    console.log(
      `[GOG] Page ${currentPage}/${totalPages} fetched (${data.products.length} games)`,
    );

    currentPage++;

    // Rate-limit: 500 ms between page requests
    if (currentPage <= totalPages) {
      await new Promise((resolve) => setTimeout(resolve, 500));
    }
  } while (currentPage <= totalPages);

  console.log(`[GOG] Library complete: ${allGames.length} games total`);

  return allGames;
}

// ── Cover URL helper ─────────────────────────────────────────────────────────

/**
 * Convert a GOG image base path into a full HTTPS cover URL.
 *
 * GOG images are returned as protocol-relative paths like
 * `//images-1.gog.com/xxx`.  This helper ensures HTTPS and optionally
 * appends a size suffix (e.g. `_196.jpg`).
 *
 * @param imageBase  The raw image path returned by the GOG API
 * @param size       Optional size suffix to append (e.g. `_196.jpg`)
 */
export function gogCoverUrl(imageBase: string, size?: string): string {
  let url = imageBase;

  // Ensure HTTPS prefix
  if (url.startsWith('//')) {
    url = `https:${url}`;
  } else if (!url.startsWith('http')) {
    url = `https://${url}`;
  }

  // Append size suffix if provided
  if (size) {
    url = `${url}${size}`;
  }

  return url;
}
