/**
 * Tests for GET /api/profile/me/demographics
 *
 * Covers:
 *   - returns all-null fields when Profile row has no demographics yet
 *   - returns 401 when not authenticated
 *   - returns saved values when row is populated
 *   - returns withdrawnAt when data was withdrawn
 */
import { describe, expect, it, vi, beforeEach } from "vitest";

const mocks = vi.hoisted(() => ({
  profile: {
    findUnique: vi.fn(),
  },
  requireUser: vi.fn(),
}));

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

vi.mock("../../server/utils/auth", () => ({
  requireUser: mocks.requireUser,
}));

import { getDemographics } from "../../server/db/profile";

beforeEach(() => {
  vi.clearAllMocks();
});

// ─── getDemographics DB-layer ─────────────────────────────────────────────

describe("getDemographics — all-null row", () => {
  it("returns null for all 9 demographic fields + consent fields when not yet filled", async () => {
    mocks.profile.findUnique.mockResolvedValueOnce({
      birthYear: null,
      gender: null,
      maritalStatus: null,
      employmentStatus: null,
      shiftWork: null,
      industry: null,
      jobTenure: null,
      bundesland: null,
      city: null,
      demographicsConsentAt: null,
      demographicsWithdrawnAt: null,
    });

    const result = await getDemographics("user-1");

    expect(result).toEqual({
      birthYear: null,
      gender: null,
      maritalStatus: null,
      employmentStatus: null,
      shiftWork: null,
      industry: null,
      jobTenure: null,
      bundesland: null,
      city: null,
      consentAt: null,
      withdrawnAt: null,
    });

    expect(mocks.profile.findUnique).toHaveBeenCalledWith({
      where: { id: "user-1" },
      select: expect.objectContaining({
        birthYear: true,
        gender: true,
        demographicsConsentAt: true,
        demographicsWithdrawnAt: true,
      }),
    });
  });
});

describe("getDemographics — 404 when profile missing", () => {
  it("throws 404 when profile row does not exist", async () => {
    mocks.profile.findUnique.mockResolvedValueOnce(null);

    await expect(getDemographics("ghost-user")).rejects.toMatchObject({
      statusCode: 404,
    });
  });
});

describe("getDemographics — populated row", () => {
  it("returns ISO strings for dates and correct field values", async () => {
    const consentDate = new Date("2026-04-01T10:00:00Z");
    mocks.profile.findUnique.mockResolvedValueOnce({
      birthYear: 1989,
      gender: "male",
      maritalStatus: "single",
      employmentStatus: "employed",
      shiftWork: false,
      industry: "IT",
      jobTenure: "3_5y",
      bundesland: "DE-BY",
      city: "München",
      demographicsConsentAt: consentDate,
      demographicsWithdrawnAt: null,
    });

    const result = await getDemographics("user-2");

    expect(result.birthYear).toBe(1989);
    expect(result.gender).toBe("male");
    expect(result.consentAt).toBe("2026-04-01T10:00:00.000Z");
    expect(result.withdrawnAt).toBeNull();
  });
});

describe("getDemographics — withdrawn row", () => {
  it("returns withdrawnAt as ISO string when data was withdrawn", async () => {
    const consentDate = new Date("2026-03-01T00:00:00Z");
    const withdrawnDate = new Date("2026-04-15T12:00:00Z");
    mocks.profile.findUnique.mockResolvedValueOnce({
      birthYear: null,
      gender: null,
      maritalStatus: null,
      employmentStatus: null,
      shiftWork: null,
      industry: null,
      jobTenure: null,
      bundesland: null,
      city: null,
      demographicsConsentAt: consentDate,
      demographicsWithdrawnAt: withdrawnDate,
    });

    const result = await getDemographics("user-3");

    expect(result.consentAt).toBe("2026-03-01T00:00:00.000Z");
    expect(result.withdrawnAt).toBe("2026-04-15T12:00:00.000Z");
    // all data fields nulled after withdrawal
    expect(result.birthYear).toBeNull();
    expect(result.city).toBeNull();
  });
});

// ─── 401 guard (endpoint-level) ───────────────────────────────────────────
// We test the auth guard by importing the handler and simulating a
// requireUser rejection — no real Nitro boot needed.

describe("demographics.get endpoint — 401 when not authenticated", () => {
  it("propagates the 401 error from requireUser", async () => {
    const authError = Object.assign(new Error("Unauthorized"), {
      statusCode: 401,
    });
    mocks.requireUser.mockRejectedValueOnce(authError);

    // Import handler (defineEventHandler stub in setup.ts returns the fn as-is)
    const mod = await import(
      "../../server/api/profile/me/demographics.get"
    );
    const handler =
      typeof mod.default === "function" ? mod.default : (mod.default as { handler?: unknown }).handler;

    await expect(
      (handler as (e: unknown) => Promise<unknown>)({ body: null }),
    ).rejects.toMatchObject({ statusCode: 401 });
  });
});
