/**
 * Tests for GET /api/social/profile/[userId] — postsCount + followingCount
 *
 * Covers:
 *   - postsCount reflects live communityPost.count (not 0 when posts exist)
 *   - followingCount reflects live userFollow.count
 *   - followersCount passes through from profile row (denormalized)
 */
import { describe, expect, it, vi, beforeEach } from "vitest";

const mocks = vi.hoisted(() => ({
  communityPost: {
    findMany: vi.fn(),
    count: vi.fn(),
  },
  userFollow: {
    findUnique: vi.fn(),
    count: vi.fn(),
  },
  profile: {
    findUnique: vi.fn(),
  },
  userScore: {
    findUnique: vi.fn(),
  },
}));

vi.mock("../../server/utils/prisma", () => ({
  usePrisma: () => ({
    communityPost: mocks.communityPost,
    userFollow: mocks.userFollow,
    profile: mocks.profile,
    userScore: mocks.userScore,
  }),
}));

vi.mock("../../server/utils/auth", () => ({
  requireUser: vi.fn().mockRejectedValue(
    Object.assign(new Error("Unauthorized"), { statusCode: 401 }),
  ),
}));

vi.mock("../../server/db/profile", () => ({
  getProfile: vi.fn().mockResolvedValue({
    id: "user-1",
    username: "testuser",
    followersCount: 3,
    createdAt: new Date("2026-01-01T00:00:00Z"),
  }),
}));

vi.mock("../../server/db/scores", () => ({
  getUserScore: vi.fn().mockResolvedValue({ tier: "beginner", totalPoints: 0 }),
}));

vi.mock("../../server/db/social", () => ({
  getFollowRelation: vi.fn().mockResolvedValue(null),
}));

vi.mock("../../server/utils/getUsersMeta", () => ({
  getUsersMeta: vi.fn().mockResolvedValue({
    "user-1": { nickname: "Tester", avatar: null },
  }),
}));

// Stub Nitro globals needed by the endpoint file
const g = globalThis as Record<string, unknown>;
if (typeof g.getRouterParam === "undefined") {
  g.getRouterParam = (_event: unknown, key: string) =>
    key === "userId" ? "user-1" : undefined;
}

beforeEach(() => {
  vi.clearAllMocks();
  mocks.communityPost.findMany.mockResolvedValue([]);
  mocks.communityPost.count.mockResolvedValue(0);
  mocks.userFollow.count.mockResolvedValue(0);
  mocks.userFollow.findUnique.mockResolvedValue(null);
});

async function callHandler() {
  const mod = await import("../../server/api/social/profile/[userId].get");
  const handler =
    typeof mod.default === "function"
      ? mod.default
      : (mod.default as { handler?: unknown }).handler;
  return (handler as (e: unknown) => Promise<unknown>)({ body: null });
}

describe("postsCount", () => {
  it("returns postsCount > 0 when user has unmoderated posts", async () => {
    mocks.communityPost.count.mockResolvedValueOnce(5);
    mocks.userFollow.count.mockResolvedValueOnce(2);

    const result = (await callHandler()) as Record<string, unknown>;

    expect(result.postsCount).toBe(5);
    expect(mocks.communityPost.count).toHaveBeenCalledWith({
      where: { userId: "user-1", isModerated: false },
    });
  });

  it("returns postsCount = 0 when user has no posts", async () => {
    mocks.communityPost.count.mockResolvedValueOnce(0);
    mocks.userFollow.count.mockResolvedValueOnce(0);

    const result = (await callHandler()) as Record<string, unknown>;

    expect(result.postsCount).toBe(0);
  });
});

describe("followingCount", () => {
  it("returns followingCount from userFollow.count", async () => {
    mocks.communityPost.count.mockResolvedValueOnce(2);
    mocks.userFollow.count.mockResolvedValueOnce(7);

    const result = (await callHandler()) as Record<string, unknown>;

    expect(result.followingCount).toBe(7);
    expect(mocks.userFollow.count).toHaveBeenCalledWith({
      where: { followerId: "user-1" },
    });
  });
});

describe("followersCount", () => {
  it("passes through denormalized followersCount from profile row", async () => {
    mocks.communityPost.count.mockResolvedValueOnce(0);
    mocks.userFollow.count.mockResolvedValueOnce(0);

    const result = (await callHandler()) as Record<string, unknown>;

    expect(result.followersCount).toBe(3);
  });
});
