import { describe, it, expect, vi, beforeEach } from "vitest";
import fastify from "fastify";
import { registerBallSkinPackRoutes } from "../ball-skin-pack-routes.js";
import { makeCtx } from "./helpers.js";

const makeAuthCtx = (userId = 42) => {
  const executeFn = vi
    .fn()
    // GET /ball-skins/user/:userId → user_ball_skins
    .mockResolvedValueOnce([
      [{ skin_id: "neon_blue" }, { skin_id: "fire_red" }],
    ])
    // getAllActivePacks → ball_skin_packs
    .mockResolvedValueOnce([
      [
        {
          id: 1,
          pack_id: "starter",
          name: "Starter Skins",
          description: "Basic skins",
          price: 2.99,
          skin_ids: '["neon_blue","neon_green"]',
          skin_count: 2,
          is_active: 1,
        },
      ],
    ])
    // userOwnsPack
    .mockResolvedValueOnce([[]])
    .mockResolvedValue([{ affectedRows: 1 }]);

  return makeCtx({
    db: { execute: executeFn } as any,
    requireAuth: async (request: any) => {
      request.user = { sub: userId };
    },
  });
};

describe("ball-skin-pack-routes", () => {
  beforeEach(() => vi.clearAllMocks());

  describe("GET /ball-skins/user/:userId", () => {
    it("retourne les skins possédés par l'utilisateur", async () => {
      const app = fastify();
      await registerBallSkinPackRoutes(app, makeAuthCtx(42));

      const res = await app.inject({
        method: "GET",
        url: "/ball-skins/user/42",
      });
      expect(res.statusCode).toBe(200);
      const body = JSON.parse(res.body);
      expect(body.skins).toContain("neon_blue");
      expect(body.skins).toContain("fire_red");
    });

    it("retourne 403 si userId ne correspond pas", async () => {
      const app = fastify();
      await registerBallSkinPackRoutes(app, makeAuthCtx(42));

      const res = await app.inject({
        method: "GET",
        url: "/ball-skins/user/99",
      });
      expect(res.statusCode).toBe(403);
    });

    it("retourne 400 pour userId non numérique", async () => {
      const app = fastify();
      await registerBallSkinPackRoutes(app, makeAuthCtx(42));

      const res = await app.inject({
        method: "GET",
        url: "/ball-skins/user/abc",
      });
      expect(res.statusCode).toBe(400);
    });
  });

  describe("GET /ball-skin-packs", () => {
    it("retourne la liste des packs de skins", async () => {
      const ctx = makeAuthCtx(42);
      // override pour getAllActivePacks (premier appel est pour /ball-skins/user)
      (ctx.db.execute as any)
        .mockReset()
        .mockResolvedValueOnce([
          [
            {
              id: 1,
              pack_id: "starter",
              name: "Starter",
              description: null,
              price: 2.99,
              skin_ids: "[]",
              skin_count: 2,
              is_active: 1,
            },
          ],
        ])
        .mockResolvedValue([[]]);

      const app = fastify();
      await registerBallSkinPackRoutes(app, ctx);

      const res = await app.inject({
        method: "GET",
        url: "/ball-skin-packs",
      });
      expect(res.statusCode).toBe(200);
      const body = JSON.parse(res.body);
      expect(body.packs).toBeDefined();
    });
  });

  describe("GET /ball-skin-packs/:packId", () => {
    it("retourne 404 pour un pack inexistant", async () => {
      const ctx = makeAuthCtx(42);
      (ctx.db.execute as any).mockReset().mockResolvedValue([[]]);

      const app = fastify();
      await registerBallSkinPackRoutes(app, ctx);

      const res = await app.inject({
        method: "GET",
        url: "/ball-skin-packs/unknown",
      });
      expect(res.statusCode).toBe(404);
    });
  });

  describe("GET /ball-skin-packs/user/:userId", () => {
    it("retourne les packs possédés", async () => {
      const ctx = makeAuthCtx(42);
      (ctx.db.execute as any).mockReset().mockResolvedValueOnce([
        [
          {
            pack_id: "starter",
            name: "Starter",
            description: null,
            price: 2.99,
            skin_ids: "[]",
            skin_count: 2,
            is_active: 1,
            purchased_at: "2025-01-01",
          },
        ],
      ]);

      const app = fastify();
      await registerBallSkinPackRoutes(app, ctx);

      const res = await app.inject({
        method: "GET",
        url: "/ball-skin-packs/user/42",
      });
      expect(res.statusCode).toBe(200);
      const body = JSON.parse(res.body);
      expect(body.ownedPacks).toBeDefined();
    });
  });
});
