import { describe, test, afterEach } from "node:test";
import assert from "node:assert/strict";
import { mkdtempSync, rmSync, writeFileSync, mkdirSync } from "node:fs";
import { join } from "node:path";
import { tmpdir } from "node:os";
import { generateMonthlyReport } from "../src/reports/monthly.js";
import { saveBatch } from "../src/utils/storage.js";
import type { PostAnalytics, AnalyticsBatch, MonthlyReport } from "../src/models/types.js";

function createPost(date: string, impressions: number, engagementRate: number): PostAnalytics {
  return {
    id: `post-${date}-${impressions}`,
    title: `Post on ${date}`,
    publishedDate: date,
    metrics: {
      impressions,
      reactions: Math.round(impressions * 0.05),
      comments: Math.round(impressions * 0.01),
      shares: Math.round(impressions * 0.005),
      clicks: Math.round(impressions * 0.02),
      engagementRate,
    },
    importedAt: "2026-04-01T00:00:00Z",
    exportSource: "test.csv",
  };
}

function createBatch(posts: PostAnalytics[]): AnalyticsBatch {
  const dates = posts.map(p => p.publishedDate).sort();
  return {
    batchId: "test-batch-" + Math.random().toString(36).slice(2, 10),
    importedAt: "2026-04-01T00:00:00Z",
    exportFilename: "test.csv",
    dateRange: { from: dates[0], to: dates[dates.length - 1] },
    postCount: posts.length,
    posts,
  };
}

let tmpDir: string;

function setupTestRoot(posts: PostAnalytics[]): string {
  tmpDir = mkdtempSync(join(tmpdir(), "monthly-test-"));
  for (const dir of ["exports", "posts", "weekly-reports", "monthly-reports"]) {
    mkdirSync(join(tmpDir, dir), { recursive: true });
  }
  if (posts.length > 0) {
    saveBatch(tmpDir, createBatch(posts));
  }
  return tmpDir;
}

afterEach(() => {
  if (tmpDir) rmSync(tmpDir, { recursive: true, force: true });
});

describe("generateMonthlyReport", () => {
  const marchPosts: PostAnalytics[] = [
    createPost("2026-03-03", 1000, 3.0),
    createPost("2026-03-05", 2000, 4.0),
    createPost("2026-03-10", 1500, 3.5),
    createPost("2026-03-17", 3000, 5.0),
    createPost("2026-03-24", 2500, 4.5),
  ];

  const febPosts: PostAnalytics[] = [
    createPost("2026-02-03", 800, 2.5),
    createPost("2026-02-10", 1200, 3.0),
    createPost("2026-02-17", 900, 2.8),
  ];

  test("filters posts to correct month", () => {
    const root = setupTestRoot([...marchPosts, ...febPosts]);
    const report = generateMonthlyReport(root, "2026-03");
    assert.equal(report.summary.totalPosts, 5);
  });

  test("calculates correct monthly totals", () => {
    const root = setupTestRoot(marchPosts);
    const report = generateMonthlyReport(root, "2026-03");
    assert.equal(report.summary.totalImpressions, 10000); // 1000+2000+1500+3000+2500
    assert.equal(report.summary.totalPosts, 5);
    assert.equal(report.summary.avgImpressionsPerPost, 2000);
  });

  test("sums saves into totalSaves when posts carry manual saves data", () => {
    const withSaves = (p: PostAnalytics, saves: number): PostAnalytics => ({
      ...p,
      metrics: { ...p.metrics, saves },
    });
    const posts: PostAnalytics[] = [
      withSaves(createPost("2026-03-03", 1000, 3.0), 8),
      createPost("2026-03-05", 2000, 4.0), // no saves — partial coverage
      withSaves(createPost("2026-03-10", 1500, 3.5), 13),
    ];
    const root = setupTestRoot(posts);
    const report = generateMonthlyReport(root, "2026-03");
    assert.equal(report.summary.totalSaves, 21, "totalSaves should sum 8 + 13");
  });

  test("leaves totalSaves undefined for saves-free months (backward-compat)", () => {
    const root = setupTestRoot(marchPosts);
    const report = generateMonthlyReport(root, "2026-03");
    assert.equal(report.summary.totalSaves, undefined);
  });

  test("generates weekly breakdown within month", () => {
    const root = setupTestRoot(marchPosts);
    const report = generateMonthlyReport(root, "2026-03");
    assert.ok(report.byWeek.length > 0);
    const totalPostsInWeeks = report.byWeek.reduce((sum, w) => sum + w.postCount, 0);
    assert.equal(totalPostsInWeeks, 5);
  });

  test("calculates MoM deltas when previous month exists", () => {
    const root = setupTestRoot([...febPosts, ...marchPosts]);
    // First generate February report so it exists for comparison
    generateMonthlyReport(root, "2026-02");
    const report = generateMonthlyReport(root, "2026-03");

    assert.notEqual(report.trends.comparedTo, null);
    assert.equal(report.trends.comparedTo, "2026-02");
    assert.notEqual(report.trends.percentChange.impressions, null);
    assert.notEqual(report.trends.percentChange.postCount, null);
  });

  test("handles no previous month data", () => {
    const root = setupTestRoot(marchPosts);
    const report = generateMonthlyReport(root, "2026-03");
    assert.equal(report.trends.comparedTo, null);
    assert.equal(report.trends.percentChange.impressions, null);
    assert.equal(report.trends.percentChange.engagement, null);
  });

  test("handles month with no posts", () => {
    const root = setupTestRoot(marchPosts);
    const report = generateMonthlyReport(root, "2026-01");
    assert.equal(report.summary.totalPosts, 0);
    assert.equal(report.summary.totalImpressions, 0);
    assert.equal(report.summary.avgImpressionsPerPost, 0);
    assert.equal(report.byWeek.length, 0);
  });

  test("identifies top performers", () => {
    const root = setupTestRoot(marchPosts);
    const report = generateMonthlyReport(root, "2026-03");
    assert.ok(report.topPerformers.length > 0);
    assert.equal(report.topPerformers[0].metrics.impressions, 3000);
  });

  test("sets correct month field", () => {
    const root = setupTestRoot(marchPosts);
    const report = generateMonthlyReport(root, "2026-03");
    assert.equal(report.month, "2026-03");
  });
});
