• Compile final match results from cached data with confidence scores.

    Applies filtering, creates match results with confidence scores, and includes source info.

    Parameters

    • mangaList: KenmeiManga[]

      Full list of Kenmei manga.

    • storage: CachedResultsStorage
    • checkCancellation: () => void

      Cancellation check function.

    • updateProgress: (index: number, title?: string) => void

      Progress update callback.

    • shouldUseWorkers: boolean = true

      Whether to use Web Workers for parallel processing (default: true).

    Returns Promise<MangaMatchResult[]>

    Array of complete match results.

    export async function compileMatchResults(
    mangaList: KenmeiManga[],
    storage: CachedResultsStorage,
    checkCancellation: () => void,
    updateProgress: (index: number, title?: string) => void,
    shouldUseWorkers = true,
    ): Promise<MangaMatchResult[]> {
    const results: MangaMatchResult[] = [];

    // Load existing match results to preserve statuses
    const existingResults = getSavedMatchResults() || [];
    const existingById = new Map<string, MangaMatchResult>();
    const existingByTitle = new Map<string, MangaMatchResult>();

    for (const result of existingResults) {
    if (result.kenmeiManga.id) {
    existingById.set(
    String(result.kenmeiManga.id),
    result as MangaMatchResult,
    );
    }
    existingByTitle.set(
    result.kenmeiManga.title.toLowerCase(),
    result as MangaMatchResult,
    );
    }

    // Helper function to preserve status from existing result
    const preserveExistingStatus = (
    newResult: MangaMatchResult,
    manga: KenmeiManga,
    ): void => {
    let existingResult = manga.id
    ? existingById.get(String(manga.id))
    : undefined;
    existingResult ??= existingByTitle.get(manga.title.toLowerCase());

    if (existingResult?.status && existingResult.status !== "pending") {
    newResult.status = existingResult.status;
    newResult.selectedMatch = existingResult.selectedMatch;
    newResult.matchDate = existingResult.matchDate;
    }
    };

    const {
    cachedResults,
    cachedComickSources,
    cachedMangaDexSources,
    cachedFallbackIndices,
    } = storage;
    const fallbackIndices = cachedFallbackIndices;

    // First fill in the results array to match the mangaList length
    for (let i = 0; i < mangaList.length; i++) {
    results[i] = {
    kenmeiManga: mangaList[i],
    anilistMatches: [],
    status: "pending",
    } as MangaMatchResult; // Use empty arrays instead of null

    // Initialize empty Comick source maps for missing entries
    if (!cachedComickSources[i]) {
    cachedComickSources[i] = new Map();
    }
    if (!cachedMangaDexSources[i]) {
    cachedMangaDexSources[i] = new Map();
    }
    }
    const matchConfig = getMatchConfig();

    // Try using workers for parallel processing if enabled
    if (shouldUseWorkers) {
    const workerResults = await processWithWorkers(
    mangaList,
    cachedResults,
    matchConfig,
    {
    cachedComickSources,
    cachedMangaDexSources,
    checkCancellation,
    updateProgress,
    fallbackIndices,
    preserveExistingStatus,
    },
    );

    if (workerResults) {
    return workerResults.filter((result) => result !== null);
    }
    // Fall through to synchronous processing if workers failed
    }

    // Fallback: Synchronous processing on main thread
    for (let i = 0; i < mangaList.length; i++) {
    // Check for cancellation periodically
    if (i % 10 === 0) {
    checkCancellation();
    }

    const manga = mangaList[i];
    let potentialMatches = cachedResults[i] || [];

    // Apply filtering rules based on match configuration
    const isFallback = fallbackIndices?.has(i);
    potentialMatches = applyMatchFiltering(
    potentialMatches,
    manga.title,
    matchConfig,
    manga,
    { skipSystemFilters: isFallback },
    );

    // Update progress for any remaining manga
    updateProgress(i, manga.title);

    // Create match result for this manga
    const comickSourceMap = cachedComickSources[i] || new Map();
    const mangaDexSourceMap = cachedMangaDexSources[i] || new Map();
    const newResult = createMangaMatchResult(
    manga,
    potentialMatches,
    comickSourceMap,
    mangaDexSourceMap,
    );

    // Preserve status from existing result if it's not "pending"
    preserveExistingStatus(newResult, manga);

    results[i] = newResult;
    }

    // Filter out any null entries (though there shouldn't be any)
    return results.filter((result) => result !== null);
    }