• Applies statistics filters to match results and reading history.

    Parameters

    Returns { matchResults: NormalizedMatchForStats[]; readingHistory: ReadingHistory }

    Filtered match results and reading history.

    export function applyStatisticsFilters(
    matchResults: NormalizedMatchForStats[],
    readingHistory: ReadingHistory,
    filters: import("@/types/statistics").StatisticsFilters,
    ): {
    matchResults: NormalizedMatchForStats[];
    readingHistory: ReadingHistory;
    } {
    let filteredMatches = matchResults;

    // Filter by genres
    if (filters.genres.length > 0) {
    filteredMatches = filteredMatches.filter((match) => {
    const genres = match.selectedMatch?.genres ?? [];
    return filters.genres.some((filterGenre) => genres.includes(filterGenre));
    });
    }

    // Filter by formats
    if (filters.formats.length > 0) {
    filteredMatches = filteredMatches.filter((match) => {
    const format = match.selectedMatch?.format;
    return format && filters.formats.includes(format);
    });
    }

    // Filter by tags
    if (filters.tags.length > 0) {
    filteredMatches = filteredMatches.filter((match) => {
    const tags = match.selectedMatch?.tags ?? [];
    return filters.tags.some((filterTag) => tags.includes(filterTag));
    });
    }

    // Filter by statuses
    if (filters.statuses.length > 0) {
    filteredMatches = filteredMatches.filter((match) =>
    filters.statuses.includes(match.status),
    );
    }

    // Filter by date range
    if (filters.dateRange.start || filters.dateRange.end) {
    filteredMatches = filteredMatches.filter((match) => {
    if (!match.matchDate) return false;
    const matchTime = match.matchDate.getTime();
    if (
    filters.dateRange.start &&
    matchTime < filters.dateRange.start.getTime()
    ) {
    return false;
    }
    if (
    filters.dateRange.end &&
    matchTime > filters.dateRange.end.getTime()
    ) {
    return false;
    }
    return true;
    });
    }

    // Filter by confidence range
    // Try to read confidence from selectedMatch first, fall back to max of all anilistMatches
    if (filters.confidenceRange.min > 0 || filters.confidenceRange.max < 100) {
    filteredMatches = filteredMatches.filter((match) => {
    let confidence = 0;
    // Prefer selectedMatch confidence if available
    if (match.selectedMatch?.confidence !== undefined) {
    confidence = match.selectedMatch.confidence;
    } else if (match.anilistMatches && match.anilistMatches.length > 0) {
    // Use maximum confidence across all anilist matches
    const validConfidences = match.anilistMatches
    .map((m) => m.confidence ?? 0)
    .filter((c) => typeof c === "number" && c >= 0);
    confidence =
    validConfidences.length > 0 ? Math.max(...validConfidences) : 0;
    }
    return (
    confidence >= filters.confidenceRange.min &&
    confidence <= filters.confidenceRange.max
    );
    });
    }

    // Cross-reference reading history with filtered matches
    const filteredMangaIds = new Set(
    filteredMatches.map((m) => String(m.kenmeiManga.id)),
    );
    const filteredEntries = readingHistory.entries.filter((entry) =>
    filteredMangaIds.has(String(entry.mangaId)),
    );
    const filteredHistory: ReadingHistory = {
    entries: filteredEntries,
    lastUpdated: readingHistory.lastUpdated,
    version: readingHistory.version,
    };

    return {
    matchResults: filteredMatches,
    readingHistory: filteredHistory,
    };
    }