• Analyzes time-of-day skip patterns

    Performs a comprehensive analysis of when users tend to skip tracks throughout the day, week, and across different time periods. This function identifies temporal patterns in listening behavior, such as peak skip hours, day of week trends, and weekday vs. weekend differences.

    The analysis includes:

    • Hourly distribution of skips across 24 hours
    • Percentage-based normalization to account for overall listening volume
    • Identification of peak skip hours (when users are most likely to skip)
    • Low skip periods (when users are most engaged)
    • Time-of-day categorization (morning, afternoon, evening, night)
    • Day-of-week distribution patterns
    • Weekday vs. weekend comparison

    This analysis helps identify optimal listening times and pattern differences that may correlate with user mood, activity level, or environmental factors.

    Returns Promise<
        {
            hourlyDistribution: number[];
            hourlyPercentages: number[];
            peakSkipHours: number[];
            lowSkipHours: number[];
            morningSkips: number;
            afternoonSkips: number;
            eveningSkips: number;
            nightSkips: number;
            totalSkips: number;
            skipsByDayOfWeek: number[];
            weekdayVsWeekendSkips: {
                weekday: { count: number; percentage: number };
                weekend: { count: number; percentage: number };
            };
        },
    >

    Promise resolving to a detailed time-based pattern analysis object

    // Get time-based skip patterns for visualization
    const timePatterns = await analyzeTimeOfDaySkipPatterns();
    renderHourlyChart(timePatterns.hourlyDistribution);
    highlightPeakHours(timePatterns.peakSkipHours);
    export async function analyzeTimeOfDaySkipPatterns(): Promise<{
    hourlyDistribution: number[];
    hourlyPercentages: number[];
    peakSkipHours: number[];
    lowSkipHours: number[];
    morningSkips: number;
    afternoonSkips: number;
    eveningSkips: number;
    nightSkips: number;
    totalSkips: number;
    skipsByDayOfWeek: number[];
    weekdayVsWeekendSkips: {
    weekday: { count: number; percentage: number };
    weekend: { count: number; percentage: number };
    };
    }> {
    try {
    // Get user data path
    const skippedTracksFilePath = join(
    getUserDataFolder(),
    "skipped_tracks.json",
    );

    if (!existsSync(skippedTracksFilePath)) {
    return getDefaultTimeOfDayResult();
    }

    const skippedTracks: SkippedTrack[] =
    readJsonSync(skippedTracksFilePath, { throws: false }) || [];

    // Initialize result structure with explicit types for arrays that were causing errors
    const result = {
    hourlyDistribution: Array(24).fill(0),
    hourlyPercentages: Array(24).fill(0),
    peakSkipHours: [] as number[],
    lowSkipHours: [] as number[],
    morningSkips: 0,
    afternoonSkips: 0,
    eveningSkips: 0,
    nightSkips: 0,
    totalSkips: 0,
    skipsByDayOfWeek: Array(7).fill(0),
    weekdayVsWeekendSkips: {
    weekday: { count: 0, percentage: 0 },
    weekend: { count: 0, percentage: 0 },
    },
    };

    // Process each skipped track's time data
    skippedTracks.forEach((track) => {
    // If we have hourly data - use timeOfDay instead of timeOfDayData
    if (track.timeOfDay && typeof track.timeOfDay === "object") {
    // Convert timeOfDay object to array format
    const hourlyData = Array(24).fill(0);

    // Process the timeOfDay object which contains string hour keys
    Object.entries(track.timeOfDay).forEach(([hourKey, count]) => {
    const hour = parseInt(hourKey, 10);
    if (!isNaN(hour) && hour >= 0 && hour < 24) {
    hourlyData[hour] = count;
    }
    });

    for (let hour = 0; hour < 24; hour++) {
    result.hourlyDistribution[hour] += hourlyData[hour];

    // Add to time of day groups
    if (hour >= 5 && hour <= 11) {
    result.morningSkips += hourlyData[hour];
    } else if (hour >= 12 && hour <= 17) {
    result.afternoonSkips += hourlyData[hour];
    } else if (hour >= 18 && hour <= 21) {
    result.eveningSkips += hourlyData[hour];
    } else {
    result.nightSkips += hourlyData[hour];
    }

    result.totalSkips += hourlyData[hour];
    }
    }

    // Process skip timestamps for day of week analysis
    // Use skipEvents timestamps instead of skipTimestamps
    if (track.skipEvents && Array.isArray(track.skipEvents)) {
    track.skipEvents.forEach((event) => {
    const timestamp = new Date(event.timestamp).getTime();
    if (!isNaN(timestamp)) {
    const date = new Date(timestamp);
    const dayOfWeek = date.getDay(); // 0 = Sunday, 6 = Saturday

    result.skipsByDayOfWeek[dayOfWeek]++;

    // Count weekday vs weekend
    if (dayOfWeek === 0 || dayOfWeek === 6) {
    result.weekdayVsWeekendSkips.weekend.count++;
    } else {
    result.weekdayVsWeekendSkips.weekday.count++;
    }
    }
    });
    }
    });

    // Calculate percentages
    if (result.totalSkips > 0) {
    for (let i = 0; i < 24; i++) {
    result.hourlyPercentages[i] =
    (result.hourlyDistribution[i] / result.totalSkips) * 100;
    }
    }

    // Find peak and low skip hours (top 3 and bottom 3)
    const hourlyRanked = [...result.hourlyDistribution]
    .map((count, hour) => ({ hour, count }))
    .sort((a, b) => b.count - a.count);

    // Set the peak and low hours (using the defined array types)
    result.peakSkipHours = hourlyRanked.slice(0, 3).map((h) => h.hour);
    result.lowSkipHours = hourlyRanked
    .slice(-3)
    .reverse()
    .map((h) => h.hour);

    // Calculate weekday vs weekend percentages
    const totalDayOfWeekSkips = result.skipsByDayOfWeek.reduce(
    (sum, count) => sum + count,
    0,
    );
    if (totalDayOfWeekSkips > 0) {
    result.weekdayVsWeekendSkips.weekday.percentage =
    (result.weekdayVsWeekendSkips.weekday.count / totalDayOfWeekSkips) *
    100;

    result.weekdayVsWeekendSkips.weekend.percentage =
    (result.weekdayVsWeekendSkips.weekend.count / totalDayOfWeekSkips) *
    100;
    }

    return result;
    } catch (error) {
    console.error("Error analyzing time-of-day skip patterns:", error);
    return getDefaultTimeOfDayResult();
    }
    }