import type { PostAnalytics, DayOfWeekMetrics, HeatmapReport } from "../models/types.js";

const DAY_NAMES = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];

// Convert JS getDay() (0=Sun) to ISO weekday (1=Mon, 7=Sun)
function toISOWeekday(jsDay: number): number {
  return jsDay === 0 ? 7 : jsDay;
}

/**
 * Generate a day-of-week performance heatmap from post analytics data.
 * Groups posts by day of week and calculates average metrics per day.
 */
export function generateHeatmap(posts: PostAnalytics[]): HeatmapReport {
  // Initialize buckets for all 7 days (ISO: 1=Mon to 7=Sun)
  const buckets: Map<number, PostAnalytics[]> = new Map();
  for (let i = 1; i <= 7; i++) {
    buckets.set(i, []);
  }

  // Group posts by ISO weekday
  for (const post of posts) {
    const jsDay = new Date(post.publishedDate).getUTCDay();
    const isoDay = toISOWeekday(jsDay);
    buckets.get(isoDay)!.push(post);
  }

  // Build metrics per day
  const byDayOfWeek: DayOfWeekMetrics[] = [];
  for (let isoDay = 1; isoDay <= 7; isoDay++) {
    const dayPosts = buckets.get(isoDay)!;
    const jsDay = isoDay === 7 ? 0 : isoDay;
    const dayName = DAY_NAMES[jsDay];

    if (dayPosts.length === 0) {
      byDayOfWeek.push({
        dayName,
        dayIndex: isoDay,
        postCount: 0,
        avgImpressions: 0,
        avgEngagementRate: 0,
      });
      continue;
    }

    const totalImpressions = dayPosts.reduce((sum, p) => sum + p.metrics.impressions, 0);
    const totalEngagement = dayPosts.reduce((sum, p) => sum + p.metrics.engagementRate, 0);
    const bestPost = dayPosts.reduce((best, p) =>
      p.metrics.impressions > best.metrics.impressions ? p : best
    );

    byDayOfWeek.push({
      dayName,
      dayIndex: isoDay,
      postCount: dayPosts.length,
      avgImpressions: Math.round(totalImpressions / dayPosts.length),
      avgEngagementRate: parseFloat((totalEngagement / dayPosts.length).toFixed(1)),
      bestPost,
    });
  }

  // Find best days
  const daysWithPosts = byDayOfWeek.filter(d => d.postCount > 0);
  const bestDayImpressions = daysWithPosts.length > 0
    ? daysWithPosts.reduce((best, d) => d.avgImpressions > best.avgImpressions ? d : best).dayName
    : "N/A";
  const bestDayEngagement = daysWithPosts.length > 0
    ? daysWithPosts.reduce((best, d) => d.avgEngagementRate > best.avgEngagementRate ? d : best).dayName
    : "N/A";

  // Date range
  const sortedDates = posts.map(p => p.publishedDate).sort();
  const dateRange = posts.length > 0
    ? { from: sortedDates[0], to: sortedDates[sortedDates.length - 1] }
    : { from: "", to: "" };

  return {
    generatedAt: new Date().toISOString(),
    postsAnalyzed: posts.length,
    dateRange,
    byDayOfWeek,
    bestDayImpressions,
    bestDayEngagement,
  };
}
