• Search for manga on AniList.

    Parameters

    • search: string

      Search query.

    • page: number = 1

      Page number.

    • perPage: number = 50

      Results per page.

    • Optionaltoken: string

      Optional access token.

    • OptionalbypassCache: boolean

      Optional parameter to bypass cache.

    Returns Promise<SearchResult<AniListManga>>

    Promise resolving to search results.

    export async function searchManga(
    search: string,
    page: number = 1,
    perPage: number = 50,
    token?: string,
    bypassCache?: boolean,
    ): Promise<SearchResult<AniListManga>> {
    // We'll still use cache in the renderer process to minimize IPC calls
    const cacheKey = generateCacheKey(search, page, perPage);

    // Check if we should bypass the cache
    if (!bypassCache && isCacheValid(searchCache, cacheKey)) {
    console.log(`📋 Using cached search results for: "${search}"`);
    return searchCache[cacheKey].data;
    }

    if (bypassCache) {
    console.log(
    `🚨 FORCE SEARCH: Bypassing cache for "${search}" in client.searchManga - will make API request`,
    );
    }

    console.log(`🔍 Searching for manga: "${search}" (page ${page})`);

    try {
    // Updated type parameter to correctly handle potential nested data structure
    const response = await request<{
    data?: { Page: SearchResult<AniListManga>["Page"] };
    Page?: SearchResult<AniListManga>["Page"];
    }>(SEARCH_MANGA, { search, page, perPage }, token, undefined, bypassCache);
    console.log("Query:", SEARCH_MANGA);
    console.log("Variables:", { search, page, perPage, bypassCache });
    console.log("🔍 searchManga response:", response);

    // Validate the response structure before using it
    if (!response || !response.data) {
    console.error(
    `Invalid API response when searching for "${search}":`,
    response,
    );
    throw new Error(`Invalid API response: missing data property`);
    }

    // Check if the API response has a nested data object (response.data.data structure)
    const responseData = response.data.data
    ? response.data.data
    : response.data;

    if (!responseData.Page) {
    console.error(
    `Invalid API response when searching for "${search}": missing Page property`,
    responseData,
    );
    throw new Error(`Invalid API response: missing Page property`);
    }

    const result = { Page: responseData.Page };

    // Ensure media array exists (even if empty)
    if (!result.Page.media) {
    result.Page.media = [];
    }

    // Log the number of results found
    console.log(
    `🔍 Found ${result.Page.media.length} manga for "${search}" (page ${page}/${result.Page.pageInfo?.lastPage || 1})`,
    );

    // Cache the results locally if not bypassing cache
    if (!bypassCache) {
    searchCache[cacheKey] = {
    data: result,
    timestamp: Date.now(),
    };

    // Persist the updated cache
    persistSearchCache();
    console.log(
    `💾 Cached ${result.Page.media.length} results for "${search}"`,
    );
    } else {
    console.log(
    `🚨 FORCE SEARCH: Not caching results for "${search}" as bypassCache=true`,
    );
    }

    // Signal to other components that a new search result is available
    try {
    // Notify any listeners that we have new search results
    const event = new CustomEvent("anilist:search-results-updated", {
    detail: {
    search,
    results: result.Page.media || [],
    timestamp: Date.now(),
    },
    });
    window.dispatchEvent(event);
    } catch (e) {
    console.error("Failed to dispatch search results event:", e);
    }

    return result;
    } catch (error) {
    console.error(`Error searching for manga: ${search}`, error);

    // Return a valid but empty result to prevent crashing
    const emptyResult: SearchResult<AniListManga> = {
    Page: {
    pageInfo: {
    total: 0,
    currentPage: page,
    lastPage: 1,
    hasNextPage: false,
    perPage,
    },
    media: [],
    },
    };

    return emptyResult;
    }
    }