import { describe, it, expect } from "vitest";
import { mapUserRow, toPublicUser } from "../user-service.js";
import type { UserRow, UserRecord } from "../types.js";

describe("user-service", () => {
  // ────────────── mapUserRow ──────────────

  describe("mapUserRow", () => {
    const minimalRow: UserRow = {
      id: 1,
      email: "test@example.com",
    };

    it("mappe les champs obligatoires", () => {
      const user = mapUserRow(minimalRow);
      expect(user.id).toBe(1);
      expect(user.email).toBe("test@example.com");
    });

    it("extrait le displayName depuis l'email si absent", () => {
      const user = mapUserRow(minimalRow);
      expect(user.displayName).toBe("test");
    });

    it("utilise le displayName fourni", () => {
      const user = mapUserRow({ ...minimalRow, displayName: "Bruno" });
      expect(user.displayName).toBe("Bruno");
    });

    it("fallback à 'Joueur' si email est vide", () => {
      const user = mapUserRow({ ...minimalRow, email: "@", displayName: "" });
      expect(user.displayName).toBe("Joueur");
    });

    it("convertit guest 0/1 en boolean", () => {
      expect(mapUserRow({ ...minimalRow, guest: 0 }).guest).toBe(false);
      expect(mapUserRow({ ...minimalRow, guest: 1 }).guest).toBe(true);
      expect(mapUserRow({ ...minimalRow, guest: true }).guest).toBe(true);
    });

    it("convertit isAdmin en boolean", () => {
      expect(mapUserRow({ ...minimalRow, isAdmin: 0 }).isAdmin).toBe(false);
      expect(mapUserRow({ ...minimalRow, isAdmin: 1 }).isAdmin).toBe(true);
    });

    it("convertit vipNoAds en boolean", () => {
      expect(mapUserRow({ ...minimalRow, vipNoAds: 0 }).vipNoAds).toBe(false);
      expect(mapUserRow({ ...minimalRow, vipNoAds: 1 }).vipNoAds).toBe(true);
    });

    it("gère les valeurs null pour avatar/accent/title/motto", () => {
      const user = mapUserRow(minimalRow);
      expect(user.avatar).toBeNull();
      expect(user.accent).toBeNull();
      expect(user.title).toBeNull();
      expect(user.motto).toBeNull();
    });

    it("mappe les valeurs optionnelles quand présentes", () => {
      const row: UserRow = {
        ...minimalRow,
        avatar: "avatar1",
        accent: "#ff0000",
        title: "Champion",
        motto: "Ready to roll",
        passwordHash: "hash123",
        failedAttempts: 3,
        lockedUntil: "2025-01-01",
        resetTokenHash: "tokHash",
        resetTokenExpires: "2025-02-01",
        bannedAt: "2025-03-01",
        banUntil: "2025-04-01",
        banReason: "spam",
      };
      const user = mapUserRow(row);
      expect(user.avatar).toBe("avatar1");
      expect(user.accent).toBe("#ff0000");
      expect(user.title).toBe("Champion");
      expect(user.motto).toBe("Ready to roll");
      expect(user.passwordHash).toBe("hash123");
      expect(user.failedAttempts).toBe(3);
      expect(user.banReason).toBe("spam");
    });

    it("failedAttempts default à 0 si null/undefined", () => {
      const user = mapUserRow({ ...minimalRow, failedAttempts: null });
      expect(user.failedAttempts).toBe(0);
    });

    it("failedAttempts default à 0 si NaN", () => {
      const user = mapUserRow({ ...minimalRow, failedAttempts: undefined });
      expect(user.failedAttempts).toBe(0);
    });
  });

  // ────────────── toPublicUser ──────────────

  describe("toPublicUser", () => {
    const fullUser: UserRecord = {
      id: 1,
      email: "test@example.com",
      displayName: "Bruno",
      emailVerified: true,
      avatar: "avatar1",
      accent: "#ff0000",
      title: "Champion",
      motto: "Ready",
      guest: false,
      isAdmin: true,
      vipNoAds: false,
      vipExpiresAt: null,
      passwordHash: "secrethash",
      failedAttempts: 0,
      lockedUntil: null,
      resetTokenHash: "tokenhash",
      resetTokenExpires: null,
      emailVerifiedAt: null,
      emailVerifyTokenHash: null,
      emailVerifyTokenExpires: null,
      bannedAt: null,
      banUntil: null,
      banReason: null,
    };

    it("retourne les champs publics", () => {
      const pub = toPublicUser(fullUser);
      expect(pub.id).toBe(1);
      expect(pub.email).toBe("test@example.com");
      expect(pub.displayName).toBe("Bruno");
      expect(pub.emailVerified).toBe(true);
      expect(pub.avatar).toBe("avatar1");
      expect(pub.isAdmin).toBe(true);
    });

    it("ne contient PAS les données sensibles", () => {
      const pub = toPublicUser(fullUser);
      expect("passwordHash" in pub).toBe(false);
      expect("failedAttempts" in pub).toBe(false);
      expect("lockedUntil" in pub).toBe(false);
      expect("resetTokenHash" in pub).toBe(false);
      expect("resetTokenExpires" in pub).toBe(false);
      expect("bannedAt" in pub).toBe(false);
      expect("banUntil" in pub).toBe(false);
      expect("banReason" in pub).toBe(false);
    });

    it("inclut vipNoAds et vipExpiresAt", () => {
      const pub = toPublicUser({
        ...fullUser,
        vipNoAds: true,
        vipExpiresAt: "2026-01-01",
      });
      expect(pub.vipNoAds).toBe(true);
      expect(pub.vipExpiresAt).toBe("2026-01-01");
    });
  });
});
