import { describe, it, expect, vi, beforeEach } from "vitest";
import fastify from "fastify";
import { registerProfileRoutes } from "../profile-routes.js";
import { makeCtx } from "./helpers.js";

vi.mock("../../server/admin-service.js", () => ({
  recordAudit: vi.fn(),
}));

vi.mock("../../server/user-service.js", () => ({
  toPublicUser: vi.fn((u: any) => u),
  getUserById: vi.fn(async () => ({
    id: 42,
    display_name: "NewName",
    avatar: "A",
    accent: "blue",
    motto: "hello",
    title: null,
  })),
}));

const makeAuthCtx = (userId = 42) => {
  const executeFn = vi
    .fn()
    .mockResolvedValueOnce([[]]) // check display name unique → aucun doublon
    .mockResolvedValue([{ affectedRows: 1 }]);

  return makeCtx({
    db: { execute: executeFn } as any,
    requireAuth: async (request: any) => {
      request.user = { sub: userId };
    },
  });
};

/** Payload complet valide pour PUT /profile/:userId */
const validProfilePayload = {
  displayName: "NewName",
  accent: "blue",
  motto: "Hello world",
  avatar: "A",
};

describe("profile-routes", () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  // ────────────── POST /profile/check-display-name ──────────────

  describe("POST /profile/check-display-name", () => {
    it("vérifie un displayName valide", async () => {
      const app = fastify();
      registerProfileRoutes(app, makeAuthCtx(42));

      const res = await app.inject({
        method: "POST",
        url: "/profile/check-display-name",
        payload: { displayName: "Player42" },
      });
      expect(res.statusCode).toBe(200);
    });

    it("refuse un displayName vide", async () => {
      const app = fastify();
      registerProfileRoutes(app, makeAuthCtx(42));

      const res = await app.inject({
        method: "POST",
        url: "/profile/check-display-name",
        payload: { displayName: "" },
      });
      expect(res.statusCode).toBe(400);
    });

    it("refuse sans displayName dans le payload", async () => {
      const app = fastify();
      registerProfileRoutes(app, makeAuthCtx(42));

      const res = await app.inject({
        method: "POST",
        url: "/profile/check-display-name",
        payload: {},
      });
      expect(res.statusCode).toBe(400);
    });
  });

  // ────────────── PUT /profile/:userId ──────────────

  describe("PUT /profile/:userId", () => {
    it("met à jour un profil valide", async () => {
      const app = fastify();
      registerProfileRoutes(app, makeAuthCtx(42));

      const res = await app.inject({
        method: "PUT",
        url: "/profile/42",
        payload: validProfilePayload,
      });
      expect(res.statusCode).toBe(200);
    });

    it("retourne 403 si userId ne correspond pas au token", async () => {
      const app = fastify();
      registerProfileRoutes(app, makeAuthCtx(42));

      const res = await app.inject({
        method: "PUT",
        url: "/profile/99",
        payload: validProfilePayload,
      });
      expect(res.statusCode).toBe(403);
    });

    it("refuse un displayName avec caractères HTML", async () => {
      const app = fastify();
      registerProfileRoutes(app, makeAuthCtx(42));

      const res = await app.inject({
        method: "PUT",
        url: "/profile/42",
        payload: {
          ...validProfilePayload,
          displayName: "<script>alert(1)</script>",
        },
      });
      expect(res.statusCode).toBe(400);
    });

    it("refuse un displayName trop long (>15 chars)", async () => {
      const app = fastify();
      registerProfileRoutes(app, makeAuthCtx(42));

      const res = await app.inject({
        method: "PUT",
        url: "/profile/42",
        payload: { ...validProfilePayload, displayName: "A".repeat(16) },
      });
      expect(res.statusCode).toBe(400);
    });

    it("refuse sans tous les champs requis", async () => {
      const app = fastify();
      registerProfileRoutes(app, makeAuthCtx(42));

      const res = await app.inject({
        method: "PUT",
        url: "/profile/42",
        payload: { displayName: "Test" },
      });
      // Missing accent, motto, avatar → schema validation 400
      expect(res.statusCode).toBe(400);
    });
  });
});
