• Calculates library-wide skip statistics from all collected data

    Returns Promise<
        | null
        | {
            totalSkips: number;
            totalTracks: number;
            uniqueTracksSkipped: number;
            overallSkipRate: number;
            skipsByType: Record<string, number>;
            artistsWithHighestSkipRates: {
                artistName: string;
                skipRate: number;
                totalSkips: number;
            }[];
            mostSkippedTracks: {
                trackId: string;
                trackName: string;
                artistName: string;
                skipCount: number;
            }[];
            averageSkipPercentage: number;
            skipTrends: {
                daily: Record<string, number>;
                weekly: Record<string, number>;
            };
            lastUpdated: string;
        },
    >

    Object with library-wide skip metrics

    export async function calculateLibrarySkipStatistics() {
    try {
    const skippedTracks = await getSkippedTracks();
    const dailyMetrics = await aggregateDailySkipMetrics();
    const weeklyMetrics = await aggregateWeeklySkipMetrics();
    const artistMetrics = await aggregateArtistSkipMetrics();
    const statistics = await getStatistics();

    // Define interface for skip events for type safety
    interface SkipEvent {
    timestamp: string;
    progress: number;
    isManualSkip?: boolean;
    skipType?: string;
    context?: {
    type: string;
    uri?: string;
    name?: string;
    id?: string;
    };
    }

    // Create an object to hold library-wide statistics
    const libraryStats = {
    totalSkips: 0,
    totalTracks: 0,
    uniqueTracksSkipped: 0,
    overallSkipRate: 0,
    skipsByType: {
    preview: 0,
    standard: 0,
    near_end: 0,
    manual: 0,
    auto: 0,
    } as Record<string, number>,
    artistsWithHighestSkipRates: [] as Array<{
    artistName: string;
    skipRate: number;
    totalSkips: number;
    }>,
    mostSkippedTracks: [] as Array<{
    trackId: string;
    trackName: string;
    artistName: string;
    skipCount: number;
    }>,
    averageSkipPercentage: 0,
    skipTrends: {
    daily: {} as Record<string, number>,
    weekly: {} as Record<string, number>,
    },
    lastUpdated: new Date().toISOString(),
    };

    // Calculate total skips and unique tracks skipped
    libraryStats.totalSkips = skippedTracks.reduce(
    (sum, track) => sum + (track.skipCount || 0),
    0,
    );
    libraryStats.uniqueTracksSkipped = skippedTracks.length;

    // Get total tracks from statistics
    libraryStats.totalTracks = statistics.totalUniqueTracks || 0;

    // Calculate overall skip rate
    if (libraryStats.totalTracks > 0) {
    libraryStats.overallSkipRate =
    libraryStats.uniqueTracksSkipped / libraryStats.totalTracks;
    }

    // Aggregate skips by type
    skippedTracks.forEach((track) => {
    if (track.skipTypes) {
    Object.entries(track.skipTypes).forEach(([type, count]) => {
    if (type in libraryStats.skipsByType) {
    libraryStats.skipsByType[type] += count;
    }
    });
    }

    if (track.manualSkipCount) {
    libraryStats.skipsByType.manual += track.manualSkipCount;
    }

    if (track.autoSkipCount) {
    libraryStats.skipsByType.auto += track.autoSkipCount;
    }
    });

    // Find artists with highest skip rates
    libraryStats.artistsWithHighestSkipRates = Object.values(artistMetrics)
    .filter((artist) => artist.totalSkips >= 3) // Only include artists with enough data
    .sort((a, b) => b.skipRatio - a.skipRatio)
    .slice(0, 10)
    .map((artist) => ({
    artistName: artist.artistName,
    skipRate: artist.skipRatio,
    totalSkips: artist.totalSkips,
    }));

    // Find most skipped tracks
    libraryStats.mostSkippedTracks = skippedTracks
    .sort((a, b) => (b.skipCount || 0) - (a.skipCount || 0))
    .slice(0, 10)
    .map((track) => ({
    trackId: track.id,
    trackName: track.name,
    artistName: track.artist,
    skipCount: track.skipCount || 0,
    }));

    // Calculate average skip percentage
    const tracksWithEvents = skippedTracks.filter(
    (track) => track.skipEvents && track.skipEvents.length > 0,
    );

    if (tracksWithEvents.length > 0) {
    const totalPercentage = tracksWithEvents.reduce((sum: number, track) => {
    if (!track.skipEvents) return sum;
    const trackAvg =
    track.skipEvents.reduce(
    (tSum: number, event: SkipEvent) => tSum + event.progress,
    0,
    ) / track.skipEvents.length;
    return sum + trackAvg;
    }, 0);

    libraryStats.averageSkipPercentage =
    totalPercentage / tracksWithEvents.length;
    }

    // Calculate skip trends
    // Daily trend
    const sortedDays = Object.keys(dailyMetrics).sort();
    const recentDays = sortedDays.slice(-14); // Last 14 days

    recentDays.forEach((day) => {
    libraryStats.skipTrends.daily[day] = dailyMetrics[day].tracksSkipped;
    });

    // Weekly trend
    const sortedWeeks = Object.keys(weeklyMetrics).sort();
    const recentWeeks = sortedWeeks.slice(-8); // Last 8 weeks

    recentWeeks.forEach((week) => {
    libraryStats.skipTrends.weekly[week] = weeklyMetrics[week].totalSkips;
    });

    // Store the library stats in a separate file
    const libraryStatsFilePath = join(
    ensureStatisticsDir(),
    "library_skip_statistics.json",
    );
    writeJsonSync(libraryStatsFilePath, libraryStats, { spaces: 2 });

    return libraryStats;
    } catch (error) {
    console.error("Error calculating library skip statistics:", error);
    return null;
    }
    }