import { beforeEach, describe, expect, it, vi } from "vitest";
import { submitQuote } from "@/modules/quote/orchestrator";

vi.mock("@/modules/cache/redis-cache", () => ({
  getL2: vi.fn(),
  setL2: vi.fn(),
  setL3: vi.fn(),
}));

vi.mock("@/modules/quote/idempotency", () => ({
  checkIdempotency: vi.fn(),
  saveIdempotency: vi.fn(),
}));

vi.mock("@/modules/quote/quote-id", () => ({
  generateQuoteId: vi.fn(),
  handleQuoteIdConflict: vi.fn(),
  isQuoteIdUniqueConflict: vi.fn(),
}));

vi.mock("@/modules/quote/rpa-queue", () => ({
  enqueueQuoteJob: vi.fn(),
}));

vi.mock("@/modules/pricing/engine", () => ({
  getMarkupRule: vi.fn().mockResolvedValue({ type: "percent", percent: 0, fixedAmount: 0 }),
  applyMarkupToQuotes: vi.fn((quotes: unknown[]) => quotes),
}));

vi.mock("@/lib/axel/quote-from-request", () => ({
  fetchAxelQuoteItems: vi.fn(),
}));

vi.mock("@/lib/rpa/env", () => ({
  isAxelDirectQuoteMode: vi.fn(() => true),
  isInlineDirectQuoteEnabled: vi.fn(() => true),
}));

vi.mock("@/modules/metrics/collector", () => ({
  safeRecord: vi.fn(),
  recordPostTotal: vi.fn().mockResolvedValue(undefined),
  recordCacheHit: vi.fn().mockResolvedValue(undefined),
  recordPostDone: vi.fn().mockResolvedValue(undefined),
  recordRpaTriggered: vi.fn().mockResolvedValue(undefined),
  markQuoteStarted: vi.fn().mockResolvedValue(undefined),
}));

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

import { getL2 } from "@/modules/cache/redis-cache";
import { fetchAxelQuoteItems } from "@/lib/axel/quote-from-request";
import { checkIdempotency, saveIdempotency } from "@/modules/quote/idempotency";
import { generateQuoteId } from "@/modules/quote/quote-id";
import { enqueueQuoteJob } from "@/modules/quote/rpa-queue";
import { prisma } from "@/lib/prisma";
import {
  MOTHERSHIP_DELIVERY_CONFIRMED,
  MOTHERSHIP_PICKUP_CONFIRMED,
} from "@/__tests__/fixtures/mothership-address";

const VALID_BODY = {
  request_id: "550e8400-e29b-41d4-a716-446655440000",
  customer_id: "CUST_001",
  pickup_address: {
    street: "1234 Warehouse Blvd",
    city: "Los Angeles",
    state: "CA",
    zip: "90001",
    place_id: "ChIJ_pickup",
    formatted_address: "1234 Warehouse Blvd, Los Angeles, CA 90001, USA",
    selected_from_suggestions: true,
    ...MOTHERSHIP_PICKUP_CONFIRMED,
  },
  delivery_address: {
    street: "5678 Distribution Dr",
    city: "Dallas",
    state: "TX",
    zip: "75201",
    place_id: "ChIJ_delivery",
    formatted_address: "5678 Distribution Dr, Dallas, TX 75201, USA",
    selected_from_suggestions: true,
    ...MOTHERSHIP_DELIVERY_CONFIRMED,
  },
  weight: { value: 500, unit: "lb" },
  dimensions: { length: 48, width: 40, height: 48, unit: "in" },
  pallet_count: 2,
  cargo_type: "general_freight",
};

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

const mockedCheckIdem = vi.mocked(checkIdempotency);
const mockedGetL2 = vi.mocked(getL2);
const mockedFetchInline = vi.mocked(fetchAxelQuoteItems);
const mockedGenerateId = vi.mocked(generateQuoteId);
const mockedCreate = vi.mocked(prisma.quoteRecord.create);
const mockedSaveIdem = vi.mocked(saveIdempotency);
const mockedEnqueue = vi.mocked(enqueueQuoteJob);

describe("submitQuote", () => {
  beforeEach(() => {
    vi.clearAllMocks();
    mockedCheckIdem.mockResolvedValue({ hit: false });
    mockedGetL2.mockResolvedValue(null);
    mockedGenerateId.mockResolvedValue("QTE_20260616_0001");
    mockedCreate.mockResolvedValue({} as never);
    mockedSaveIdem.mockResolvedValue(undefined);
    mockedEnqueue.mockResolvedValue(undefined);
    mockedFetchInline.mockRejectedValue(new Error("inline disabled for test"));
  });

  it("TC-105：L1 命中 → 返回原 quote_id", async () => {
    mockedCheckIdem.mockResolvedValue({
      hit: true,
      quoteId: "QTE_20260616_0001",
      response: { quote_id: "QTE_20260616_0001", status: "done" },
    });

    const result = await submitQuote(VALID_BODY);
    expect(result.quote_id).toBe("QTE_20260616_0001");
    expect(result.status).toBe("done");
    expect(mockedCreate).not.toHaveBeenCalled();
  });

  it("TC-104：L2 命中 → done + source=cache", async () => {
    mockedGetL2.mockResolvedValue({ quotes: FOUR_TIERS });

    const result = await submitQuote(VALID_BODY);
    expect(result.status).toBe("done");
    expect(result.source_type).toBe("cache");
    expect(mockedEnqueue).not.toHaveBeenCalled();
  });

  it("inline direct 成功 → done + 不入队", async () => {
    mockedFetchInline.mockResolvedValue([
      {
        serviceLevel: "standard",
        rateOption: "lowest",
        carrier: "M",
        transitDays: "5",
        transitDescription: "x",
        rawFreight: 320,
        surcharges: 0,
        rawTotal: 320,
      },
      {
        serviceLevel: "standard",
        rateOption: "fastest",
        carrier: "M",
        transitDays: "3",
        transitDescription: "x",
        rawFreight: 365,
        surcharges: 0,
        rawTotal: 365,
      },
      {
        serviceLevel: "guaranteed",
        rateOption: "lowest",
        carrier: "M",
        transitDays: "4",
        transitDescription: "x",
        rawFreight: 380,
        surcharges: 0,
        rawTotal: 380,
      },
      {
        serviceLevel: "guaranteed",
        rateOption: "fastest",
        carrier: "M",
        transitDays: "3",
        transitDescription: "x",
        rawFreight: 410,
        surcharges: 0,
        rawTotal: 410,
      },
    ] as never);

    const result = await submitQuote(VALID_BODY);
    expect(result.status).toBe("done");
    expect(result.source_type).toBe("rpa");
    expect(mockedEnqueue).not.toHaveBeenCalled();
  });

  it("inline direct 失败 → processing + 入队", async () => {
    const result = await submitQuote(VALID_BODY);
    expect(result.status).toBe("processing");
    expect(mockedEnqueue).toHaveBeenCalled();
  });
});
