import { describe, expect, it, vi, beforeEach } from "vitest";
import { detectDeviation } from "@/modules/alert/deviation-detector";

const prismaMock = vi.hoisted(() => ({
  quoteCacheMeta: {
    findUnique: vi.fn(),
    create: vi.fn(),
    update: vi.fn(),
  },
  alertLog: {
    create: vi.fn(),
  },
}));

vi.mock("@/lib/prisma", () => ({ prisma: prismaMock }));

const FOUR_TIERS = [
  {
    service_level: "standard" as const,
    rate_option: "lowest" as const,
    carrier: "M",
    transit_days: "5",
    transit_description: "x",
    raw_freight: 320,
    surcharges: 0,
    raw_total: 320,
  },
  {
    service_level: "standard" as const,
    rate_option: "fastest" as const,
    carrier: "M",
    transit_days: "3",
    transit_description: "x",
    raw_freight: 365,
    surcharges: 0,
    raw_total: 365,
  },
  {
    service_level: "guaranteed" as const,
    rate_option: "lowest" as const,
    carrier: "M",
    transit_days: "4",
    transit_description: "x",
    raw_freight: 380,
    surcharges: 0,
    raw_total: 380,
  },
  {
    service_level: "guaranteed" as const,
    rate_option: "fastest" as const,
    carrier: "M",
    transit_days: "3",
    transit_description: "x",
    raw_freight: 410,
    surcharges: 0,
    raw_total: 410,
  },
];

describe("TC-401 cache vs RPA 一致性（task-113）", () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  it("L2 raw_total 与 RPA 写入一致；偏差≥5% 触发 PRICE_DEVIATION", async () => {
    const l2RawTotal = 320;
    prismaMock.quoteCacheMeta.findUnique.mockResolvedValue({
      cargoHash: "hash_cache",
      rawTotalStandard: l2RawTotal,
    });
    prismaMock.quoteCacheMeta.update.mockResolvedValue({});
    prismaMock.alertLog.create.mockResolvedValue({});

    const newRpaQuotes = FOUR_TIERS.map((t) => ({ ...t }));
    newRpaQuotes[0].raw_total = 340;
    newRpaQuotes[0].raw_freight = 340;

    await detectDeviation("hash_cache", newRpaQuotes, "QTE_CACHE");

    expect(prismaMock.quoteCacheMeta.findUnique).toHaveBeenCalledWith({
      where: { cargoHash: "hash_cache" },
    });
    expect(prismaMock.alertLog.create).toHaveBeenCalledWith(
      expect.objectContaining({
        data: expect.objectContaining({ alertType: "PRICE_DEVIATION" }),
      }),
    );
  });

  it("L2 与 RPA 一致（偏差<5%）→ 不触发预警", async () => {
    prismaMock.quoteCacheMeta.findUnique.mockResolvedValue({
      cargoHash: "hash_ok",
      rawTotalStandard: 320,
    });
    prismaMock.quoteCacheMeta.update.mockResolvedValue({});

    await detectDeviation("hash_ok", FOUR_TIERS, "QTE_OK");

    expect(prismaMock.alertLog.create).not.toHaveBeenCalled();
  });
});
