import { describe, it, expect, beforeEach, vi } from "vitest";
import { POST } from "@/app/api/marketplace/credits/purchase/route";
import { db } from "@/lib/db";
import { auth } from "@/lib/auth";
import { stripe } from "@/lib/stripe";

vi.mock("@/lib/db", () => ({
  db: {
    user: { findUnique: vi.fn(), update: vi.fn() },
  },
}));

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

vi.mock("@/lib/stripe", () => ({
  stripe: {
    customers: { create: vi.fn() },
    checkout: { sessions: { create: vi.fn() } },
  },
}));

vi.mock("@/lib/logger", () => ({
  logger: { error: vi.fn() },
}));

describe("POST /api/marketplace/credits/purchase", () => {
  beforeEach(() => {
    vi.clearAllMocks();
    vi.mocked(db.user.findUnique).mockResolvedValue({
      id: "user_1",
      email: "u@example.com",
      stripeCustomerId: "cus_123",
    } as never);
  });

  it("returns 401 when not authenticated", async () => {
    vi.mocked(auth).mockResolvedValue(null as never);

    const res = await POST(
      new Request("http://localhost/api/marketplace/credits/purchase", {
        method: "POST",
        body: JSON.stringify({ amount_cents: 1000 }),
        headers: { "Content-Type": "application/json" },
      }),
    );
    const data = await res.json();

    expect(res.status).toBe(401);
    expect(data.error).toBe("Unauthorized");
    expect(db.user.findUnique).not.toHaveBeenCalled();
  });

  it("returns 400 when amount_cents is not allowed", async () => {
    vi.mocked(auth).mockResolvedValue({ user: { id: "user_1" } } as never);

    const res = await POST(
      new Request("http://localhost/api/marketplace/credits/purchase", {
        method: "POST",
        body: JSON.stringify({ amount_cents: 500 }),
        headers: { "Content-Type": "application/json" },
      }),
    );

    expect(res.status).toBe(400);
    expect(stripe!.checkout.sessions.create).not.toHaveBeenCalled();
  });

  it("returns 400 when amount_cents is missing", async () => {
    vi.mocked(auth).mockResolvedValue({ user: { id: "user_1" } } as never);

    const res = await POST(
      new Request("http://localhost/api/marketplace/credits/purchase", {
        method: "POST",
        body: JSON.stringify({}),
        headers: { "Content-Type": "application/json" },
      }),
    );

    expect(res.status).toBe(400);
    expect(stripe!.checkout.sessions.create).not.toHaveBeenCalled();
  });

  it("returns 200 with url when amount_cents is 10000 and Stripe creates session", async () => {
    vi.mocked(auth).mockResolvedValue({ user: { id: "user_1" } } as never);
    vi.mocked(stripe!.checkout.sessions.create).mockResolvedValue({
      url: "https://checkout.stripe.com/session_123",
    } as never);

    const res = await POST(
      new Request("http://localhost/api/marketplace/credits/purchase", {
        method: "POST",
        body: JSON.stringify({ amount_cents: 10000 }),
        headers: { "Content-Type": "application/json" },
      }),
    );
    const data = (await res.json()) as { url?: string };

    expect(res.status).toBe(200);
    expect(data.url).toBe("https://checkout.stripe.com/session_123");
    expect(stripe!.checkout.sessions.create).toHaveBeenCalledWith(
      expect.objectContaining({
        mode: "payment",
        metadata: { userId: "user_1", type: "marketplace_credits", amount_cents: "10000" },
      }),
    );
  });
});
