import { describe, expect, it } from "vitest";
import { seasonality } from "@/lib/forecast";

describe("seasonality — hệ số mùa vụ", () => {
  it("chưa đủ 6 tháng dữ liệu năm trước thì KHÔNG áp hệ số (factor = 1)", () => {
    const months = new Map([
      ["2025-04", 10],
      ["2025-05", 10],
      ["2025-06", 10],
      ["2025-07", 10],
      ["2025-08", 10],
    ]); // chỉ 5 tháng
    const { factor } = seasonality(months, "2026-08", [10, 10, 10]);
    expect(factor).toBe(1);
  });

  it("bình quân năm trước chia cho SỐ THÁNG CÒN BÁN (tính từ tháng đầu tới hết năm), không phải số tháng có dữ liệu", () => {
    // Sản phẩm bán rời rạc: có dữ liệu 6/12 tháng (Jan–Jun 2025). Bình quân đúng = tổng / 12 tháng của span
    // (tháng đầu tiên bán tới hết năm), KHÔNG PHẢI / 6 — đây chính là lỗi thật đã sửa (bình quân bị thổi gấp đôi).
    const months = new Map([
      ["2025-01", 12],
      ["2025-02", 12],
      ["2025-03", 8], // tháng đích năm sau ứng với tháng này
      ["2025-04", 12],
      ["2025-05", 12],
      ["2025-06", 12],
    ]);
    const { factor } = seasonality(months, "2026-03", [8, 8, 8]);
    // Bình quân đúng = 68 / 12 = 5,6667 → hệ số = 8 / 5,6667 ≈ 1,4118.
    // Nếu tính sai theo số tháng có dữ liệu: bình quân = 68 / 6 = 11,3333 → hệ số ≈ 0,706 — khác hẳn.
    expect(factor).toBeCloseTo(1.41176, 4);
  });

  it("tháng đích năm ngoái không có đơn nhưng sản phẩm đã bán từ trước → coi là 0 (mùa thấp), không bỏ qua hệ số", () => {
    // Bán cách tháng suốt năm 2025 (6 tháng có dữ liệu, đủ ngưỡng) nhưng KHÔNG bán vào tháng 8.
    const months = new Map([
      ["2025-01", 10],
      ["2025-03", 10],
      ["2025-05", 10],
      ["2025-07", 10],
      ["2025-09", 10],
      ["2025-11", 10],
    ]);
    const { factor } = seasonality(months, "2026-08", [1, 1, 1]);
    // targetMonthQty = 0 (không có đơn tháng 8 năm ngoái) → hệ số kẹp ở mức sàn 0,5, không phải 1 (bỏ qua).
    expect(factor).toBe(0.5);
  });

  it("hệ số được kẹp trong [0,5 – 2,0] để một tháng bất thường không kéo lệch dự báo", () => {
    const base = Object.fromEntries(["01", "02", "04", "05", "06", "07", "08", "09", "10", "11", "12"].map((m) => [`2025-${m}`, 10]));
    const spikedUp = new Map(Object.entries({ ...base, "2025-03": 1000 })); // đột biến cao
    const spikedDown = new Map(Object.entries({ ...base, "2025-03": 0.001 })); // đột biến thấp
    expect(seasonality(spikedUp, "2026-03", [10, 10, 10]).factor).toBe(2);
    expect(seasonality(spikedDown, "2026-03", [10, 10, 10]).factor).toBe(0.5);
  });
});

describe("seasonality — độ tin cậy", () => {
  it("sản lượng càng biến động (cửa sổ 3 tháng) thì độ tin cậy càng thấp", () => {
    const empty = new Map<string, number>();
    const stable = seasonality(empty, "2026-08", [10, 10, 10]).confidence;
    const volatile = seasonality(empty, "2026-08", [0, 0, 30]).confidence;
    expect(stable).toBeCloseTo(0.6, 5);
    expect(volatile).toBe(0);
    expect(volatile).toBeLessThan(stable);
  });

  it("càng nhiều tháng lịch sử thì độ tin cậy càng cao, cùng một mức ổn định", () => {
    const noHistory = seasonality(new Map(), "2026-08", [10, 10, 10]).confidence;
    const fullHistory = seasonality(new Map(Array.from({ length: 12 }, (_, i) => [`x${i}`, 1])), "2026-08", [10, 10, 10]).confidence;
    expect(fullHistory).toBeGreaterThan(noHistory);
    expect(fullHistory).toBeCloseTo(1, 5);
  });
});
