Array of normalized match results.
Reading history data.
Statistics filters to apply.
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,
};
}
Applies statistics filters to match results and reading history.