• Setup IPC handlers for AniList API requests, token exchange, cache, and shell actions.

    Returns void

    export function setupAniListAPI() {
    // Handle graphQL requests
    ipcMain.handle("anilist:request", async (_, query, variables, token) => {
    try {
    console.log("Handling AniList API request in main process");

    // Extract and remove bypassCache from variables to avoid sending it to the API
    const bypassCache = variables?.bypassCache;
    if (variables && "bypassCache" in variables) {
    // Create a copy without the bypassCache property
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    const { bypassCache: removed, ...cleanVariables } = variables;
    variables = cleanVariables;
    }

    // Check if it's a search request and if we should use cache
    const isSearchQuery = query.includes("Page(") && variables?.search;

    if (isSearchQuery && !bypassCache) {
    const cacheKey = generateCacheKey(query, variables);

    if (isCacheValid(searchCache, cacheKey)) {
    console.log(`Using cached search results for: ${variables.search}`);
    return {
    success: true,
    data: searchCache[cacheKey].data,
    };
    }
    }

    if (isSearchQuery && bypassCache) {
    console.log(`Bypassing cache for search: ${variables.search}`);
    }

    const response = await requestAniList(query, variables, token);

    // Cache search results only if not bypassing cache
    if (isSearchQuery && response.data && !bypassCache) {
    const cacheKey = generateCacheKey(query, variables);
    searchCache[cacheKey] = {
    data: response,
    timestamp: Date.now(),
    };
    }

    return {
    success: true,
    data: response,
    };
    } catch (error) {
    console.error("Error in anilist:request:", error);
    return {
    success: false,
    error,
    };
    }
    });

    // Handle token exchange
    ipcMain.handle("anilist:exchangeToken", async (_, params) => {
    try {
    const { clientId, clientSecret, redirectUri, code } = params;

    // Format the request body
    const tokenRequestBody = {
    grant_type: "authorization_code",
    client_id: clientId,
    client_secret: clientSecret,
    redirect_uri: redirectUri,
    code: code,
    };

    const response = await fetch("https://anilist.co/api/v2/oauth/token", {
    method: "POST",
    headers: {
    "Content-Type": "application/json",
    Accept: "application/json",
    },
    body: JSON.stringify(tokenRequestBody),
    });

    if (!response.ok) {
    const errorData = await response.text();
    throw new Error(`API error: ${response.status} ${errorData}`);
    }

    const data = await response.json();

    return {
    success: true,
    token: data,
    };
    } catch (error) {
    console.error("Error in anilist:exchangeToken:", error);
    return {
    success: false,
    error: error instanceof Error ? error.message : String(error),
    };
    }
    });

    // Handle opening external links in the default browser
    ipcMain.handle("shell:openExternal", async (_, url) => {
    try {
    console.log(`Opening external URL in default browser: ${url}`);
    await shell.openExternal(url);
    return { success: true };
    } catch (error) {
    console.error("Error opening external URL:", error);
    return {
    success: false,
    error: error instanceof Error ? error.message : String(error),
    };
    }
    });

    // Clear search cache
    ipcMain.handle("anilist:clearCache", (_, searchQuery) => {
    if (searchQuery) {
    // Clear specific cache entries
    Object.keys(searchCache).forEach((key) => {
    if (key.includes(searchQuery)) {
    delete searchCache[key];
    }
    });
    } else {
    // Clear all cache
    Object.keys(searchCache).forEach((key) => {
    delete searchCache[key];
    });
    }

    return { success: true };
    });

    // Get rate limit status from main process
    ipcMain.handle("anilist:getRateLimitStatus", () => {
    const now = Date.now();
    return {
    isRateLimited,
    retryAfter: isRateLimited ? rateLimitResetTime : null,
    timeRemaining: isRateLimited ? Math.max(0, rateLimitResetTime - now) : 0,
    };
    });
    }