import { beforeEach, describe, expect, it, vi } from "vitest";
import { POST } from "@/app/api/quotes/route";
import { GET as getQuote } from "@/app/api/quotes/[quote_id]/route";
import { PUT as putMarkup } from "@/app/api/markup-configs/[customer_id]/route";

vi.mock("@/modules/quote/orchestrator", () => ({
  submitQuote: vi.fn(),
}));

vi.mock("@/lib/api/rate-limit", () => ({
  enforceRateLimits: vi.fn(),
}));

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

vi.mock("@/modules/alert/service", () => ({
  writeAlert: vi.fn(),
}));

import { submitQuote } from "@/modules/quote/orchestrator";
import { enforceRateLimits } from "@/lib/api/rate-limit";
import { prisma } from "@/lib/prisma";
import { writeAlert } from "@/modules/alert/service";
import { resetServiceTokenCache } from "@/modules/auth/service-token";
import { fail } from "@/lib/response";
import {
  MOTHERSHIP_DELIVERY_CONFIRMED,
  MOTHERSHIP_PICKUP_CONFIRMED,
} from "@/__tests__/fixtures/mothership-address";

const SERVICE_HEADERS = {
  "x-auth-type": "service",
  "x-customer-id": "CUST_001",
  "x-permissions": "pricing:markup:write",
};

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",
};

beforeEach(() => {
  vi.clearAllMocks();
  resetServiceTokenCache();
  process.env.HOST_SERVICE_TOKENS = JSON.stringify({
    "demo-host-token": {
      customerId: "CUST_001",
      permissions: ["pricing:markup:write"],
    },
  });
  vi.mocked(enforceRateLimits).mockResolvedValue(null);
  vi.mocked(submitQuote).mockResolvedValue({
    quote_id: "QTE_001",
    status: "done",
    source_type: "cache",
  });
  vi.mocked(prisma.auditLog.create).mockResolvedValue({} as never);
  vi.mocked(prisma.markupConfig.upsert).mockResolvedValue({} as never);
});

describe("安全与权限集成（task-086）", () => {
  it("TC-501：越权查询他人 quote → 403 + audit", async () => {
    vi.mocked(prisma.quoteRecord.findFirst).mockResolvedValue({
      quoteId: "QTE_B",
      customerId: "CUST_B",
      requestId: "req",
      status: "done",
      currency: "USD",
      isRealtime: true,
      sourceType: "cache",
      confidenceScore: null,
      validUntil: new Date(Date.now() + 60_000),
      quotesJson: [],
      errorCode: null,
      createdAt: new Date(),
      updatedAt: new Date(),
    } as never);

    const response = await getQuote(
      new Request("http://localhost/api/quotes/QTE_B", {
        headers: SERVICE_HEADERS,
      }),
      { params: Promise.resolve({ quote_id: "QTE_B" }) },
    );

    expect(response.status).toBe(403);
    expect(prisma.auditLog.create).toHaveBeenCalledWith(
      expect.objectContaining({
        data: expect.objectContaining({ action: "FORBIDDEN_ACCESS" }),
      }),
    );
  });

  it("TC-502：无 pricing:markup:write → 403", async () => {
    const response = await putMarkup(
      new Request("http://localhost/api/markup-configs/CUST_001", {
        method: "PUT",
        headers: {
          "Content-Type": "application/json",
          "x-auth-type": "service",
          "x-customer-id": "CUST_001",
          "x-permissions": "",
        },
        body: JSON.stringify({ markup_percent: 10, operator_id: "op1" }),
      }),
      { params: Promise.resolve({ customer_id: "CUST_001" }) },
    );
    expect(response.status).toBe(403);
  });

  it("TC-503：customer 限流 → 429", async () => {
    vi.mocked(enforceRateLimits).mockResolvedValue(
      fail("RATE_LIMITED", "请求过于频繁，请稍后再试", 429),
    );

    const response = await POST(
      new Request("http://localhost/api/quotes", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          ...SERVICE_HEADERS,
          "x-forwarded-for": "10.0.0.1",
        },
        body: JSON.stringify(VALID_BODY),
      }),
    );
    expect(response.status).toBe(429);
  });

  it("TC-504：SQL 注入 street → 400 + SECURITY 预警", async () => {
    const { SecurityValidationError } = await import("@/modules/quote/types");
    vi.mocked(submitQuote).mockImplementation(() => {
      throw new SecurityValidationError("提货地址无效，请检查");
    });

    const response = await POST(
      new Request("http://localhost/api/quotes", {
        method: "POST",
        headers: { "Content-Type": "application/json", ...SERVICE_HEADERS },
        body: JSON.stringify({
          ...VALID_BODY,
          pickup_address: {
            ...VALID_BODY.pickup_address,
            street: "'; DROP TABLE quote_record; --",
          },
        }),
      }),
    );

    expect(response.status).toBe(400);
    await vi.waitFor(() => {
      expect(writeAlert).toHaveBeenCalledWith(
        "SECURITY",
        expect.any(Object),
      );
    });
  });

  it("TC-505：markup=30.1 → 400", async () => {
    const response = await putMarkup(
      new Request("http://localhost/api/markup-configs/CUST_001", {
        method: "PUT",
        headers: { "Content-Type": "application/json", ...SERVICE_HEADERS },
        body: JSON.stringify({ markup_percent: 30.1, operator_id: "op1" }),
      }),
      { params: Promise.resolve({ customer_id: "CUST_001" }) },
    );
    expect(response.status).toBe(400);
  });
});
