import { beforeEach, describe, expect, it, vi } from "vitest";
import {
  generateServiceToken,
  hashServiceToken,
} from "@/modules/customer/token-crypto";

vi.mock("@/lib/prisma", () => ({
  prisma: {
    hostCustomer: {
      findMany: vi.fn(),
      findFirst: vi.fn(),
    },
    serviceApiKey: {
      findFirst: vi.fn(),
    },
  },
}));

import { prisma } from "@/lib/prisma";
import { resolveDbServiceToken } from "@/modules/customer/customer-service";
import {
  resetServiceTokenCache,
  verifyServiceTokenAsync,
} from "@/modules/auth/service-token";

const DEMO_TOKENS = JSON.stringify({
  "demo-host-token": {
    customerId: "CUST_001",
    permissions: ["pricing:markup:write"],
  },
});

describe("verifyServiceTokenAsync", () => {
  beforeEach(() => {
    process.env.HOST_SERVICE_TOKENS = DEMO_TOKENS;
    resetServiceTokenCache();
    vi.clearAllMocks();
  });

  it("env token 仍可用", async () => {
    const result = await verifyServiceTokenAsync("demo-host-token", "CUST_001");
    expect(result.customerId).toBe("CUST_001");
  });

  it("DB token 校验通过", async () => {
    const raw = generateServiceToken();
    vi.mocked(prisma.serviceApiKey.findFirst).mockResolvedValue({
      customerId: "CUST_004",
      permissions: ["pricing:markup:write"],
      isActive: true,
      tokenHash: hashServiceToken(raw),
      customer: { status: "active", isDeleted: false },
    } as never);

    const result = await verifyServiceTokenAsync(raw, "CUST_004");
    expect(result.customerId).toBe("CUST_004");
    expect(prisma.serviceApiKey.findFirst).toHaveBeenCalled();
  });

  it("无效 token 返回 401", async () => {
    vi.mocked(prisma.serviceApiKey.findFirst).mockResolvedValue(null);
    await expect(
      verifyServiceTokenAsync("bad-token", "CUST_004"),
    ).rejects.toMatchObject({
      code: "UNAUTHORIZED",
    });
  });
});

describe("resolveDbServiceToken", () => {
  it("按 hash 解析客户", async () => {
    const raw = generateServiceToken();
    vi.mocked(prisma.serviceApiKey.findFirst).mockResolvedValue({
      customerId: "CUST_002",
      permissions: ["pricing:markup:write"],
    } as never);

    const resolved = await resolveDbServiceToken(raw);
    expect(resolved?.customerId).toBe("CUST_002");
  });
});
