import type { PostAnalytics, MonthlyReport } from "../models/types.js";
import { loadAllPosts, loadMonthlyReport, saveMonthlyReport } from "../utils/storage.js";
import { mean } from "../utils/stats.js";
import { detectAlerts } from "../utils/alerts.js";
import { getISOWeek } from "./weekly.js";

/**
 * Get previous month string (e.g., "2026-03" → "2026-02")
 */
function getPreviousMonth(month: string): string {
  const [year, m] = month.split("-").map(Number);
  if (m === 1) return `${year - 1}-12`;
  return `${year}-${String(m - 1).padStart(2, "0")}`;
}

/**
 * Generate a monthly report with optional MoM comparison.
 * Saves the report to disk and returns it.
 */
export function generateMonthlyReport(root: string, month: string): MonthlyReport {
  const allPosts = loadAllPosts(root);
  const monthPosts = allPosts.filter(p => p.publishedDate.startsWith(month));

  // Summary
  const totalPosts = monthPosts.length;
  const totalImpressions = monthPosts.reduce((s, p) => s + p.metrics.impressions, 0);
  const totalReactions = monthPosts.reduce((s, p) => s + p.metrics.reactions, 0);
  const totalComments = monthPosts.reduce((s, p) => s + p.metrics.comments, 0);
  const totalShares = monthPosts.reduce((s, p) => s + p.metrics.shares, 0);
  const totalClicks = monthPosts.reduce((s, p) => s + p.metrics.clicks, 0);
  // Optional saves: present only when ≥1 post carries manual saves data —
  // keeps saves-free months byte-identical to pre-saves output (backward-compat).
  const savesPosts = monthPosts.filter(p => p.metrics.saves !== undefined);
  const totalSaves = savesPosts.length > 0
    ? savesPosts.reduce((s, p) => s + (p.metrics.saves ?? 0), 0)
    : undefined;
  const avgEngagementRate = totalPosts > 0
    ? parseFloat(mean(monthPosts.map(p => p.metrics.engagementRate)).toFixed(2))
    : 0;
  const avgImpressionsPerPost = totalPosts > 0
    ? Math.round(totalImpressions / totalPosts)
    : 0;

  // Top performers (sorted by impressions desc)
  const topPerformers = [...monthPosts]
    .sort((a, b) => b.metrics.impressions - a.metrics.impressions)
    .slice(0, 5);

  // Weekly breakdown
  const weekBuckets = new Map<string, PostAnalytics[]>();
  for (const post of monthPosts) {
    const week = getISOWeek(new Date(post.publishedDate + "T00:00:00Z"));
    if (!weekBuckets.has(week)) weekBuckets.set(week, []);
    weekBuckets.get(week)!.push(post);
  }

  const byWeek = Array.from(weekBuckets.entries())
    .sort(([a], [b]) => a.localeCompare(b))
    .map(([week, posts]) => ({
      week,
      postCount: posts.length,
      avgImpressions: Math.round(mean(posts.map(p => p.metrics.impressions))),
      avgEngagementRate: parseFloat(mean(posts.map(p => p.metrics.engagementRate)).toFixed(1)),
    }));

  // MoM comparison
  const prevMonth = getPreviousMonth(month);
  const prevReport = loadMonthlyReport(root, prevMonth);

  let trends: MonthlyReport["trends"];
  if (prevReport && prevReport.summary.totalPosts > 0) {
    const pctImpr = prevReport.summary.totalImpressions > 0
      ? parseFloat(((totalImpressions - prevReport.summary.totalImpressions) / prevReport.summary.totalImpressions * 100).toFixed(1))
      : null;
    const pctEng = prevReport.summary.avgEngagementRate > 0
      ? parseFloat(((avgEngagementRate - prevReport.summary.avgEngagementRate) / prevReport.summary.avgEngagementRate * 100).toFixed(1))
      : null;
    const pctPosts = prevReport.summary.totalPosts > 0
      ? parseFloat(((totalPosts - prevReport.summary.totalPosts) / prevReport.summary.totalPosts * 100).toFixed(1))
      : null;

    trends = {
      comparedTo: prevMonth,
      percentChange: {
        impressions: pctImpr,
        engagement: pctEng,
        postCount: pctPosts,
      },
    };
  } else {
    trends = {
      comparedTo: null,
      percentChange: { impressions: null, engagement: null, postCount: null },
    };
  }

  // Alerts
  const alerts = totalPosts > 0 ? detectAlerts(monthPosts, "impressions") : [];

  const report: MonthlyReport = {
    month,
    generatedAt: new Date().toISOString(),
    summary: {
      totalPosts,
      totalImpressions,
      totalReactions,
      totalComments,
      totalShares,
      totalClicks,
      ...(totalSaves !== undefined ? { totalSaves } : {}),
      avgEngagementRate,
      avgImpressionsPerPost,
    },
    topPerformers,
    byWeek,
    trends,
    alerts,
  };

  // Save report
  saveMonthlyReport(root, report);

  return report;
}
