import { describe, it, expect, vi, beforeEach } from "vitest";
import fastify from "fastify";
import { registerAvatarPackRoutes } from "../avatar-pack-routes.js";
import { makeCtx } from "./helpers.js";

vi.mock("../../server/admin-service.js", () => ({
  recordAudit: vi.fn(),
}));

const makeAuthCtx = (userId = 42) => {
  const executeFn = vi
    .fn()
    // getAllActivePacks
    .mockResolvedValueOnce([
      [
        {
          id: 1,
          pack_id: "cool",
          name: "Cool Pack",
          description: "Fun avatars",
          price: 4.99,
          folder_path: "/avatars/cool",
          avatar_count: 19,
          is_active: 1,
        },
      ],
    ])
    // userOwnsAvatarPack for each pack
    .mockResolvedValueOnce([[]])
    .mockResolvedValue([{ affectedRows: 1 }]);

  return makeCtx({
    db: { execute: executeFn } as any,
    requireAuth: async (request: any) => {
      request.user = { sub: userId };
    },
  });
};

describe("avatar-pack-routes", () => {
  beforeEach(() => vi.clearAllMocks());

  describe("GET /avatar-packs", () => {
    it("retourne la liste des packs", async () => {
      const app = fastify();
      registerAvatarPackRoutes(app, makeAuthCtx(42));

      const res = await app.inject({ method: "GET", url: "/avatar-packs" });
      expect(res.statusCode).toBe(200);
      const body = JSON.parse(res.body);
      expect(body.packs).toBeDefined();
      expect(Array.isArray(body.packs)).toBe(true);
    });
  });

  describe("GET /avatar-packs/:packId", () => {
    it("retourne un pack existant", async () => {
      const ctx = makeAuthCtx(42);
      // Override execute pour getAvatarPackById
      (ctx.db.execute as any)
        .mockReset()
        .mockResolvedValueOnce([
          [
            {
              id: 1,
              pack_id: "cool",
              name: "Cool Pack",
              description: null,
              price: 4.99,
              folder_path: "/avatars/cool",
              avatar_count: 19,
              is_active: 1,
            },
          ],
        ])
        .mockResolvedValue([[]]);

      const app = fastify();
      registerAvatarPackRoutes(app, ctx);

      const res = await app.inject({
        method: "GET",
        url: "/avatar-packs/cool",
      });
      expect(res.statusCode).toBe(200);
      const body = JSON.parse(res.body);
      expect(body.pack.packId).toBe("cool");
    });

    it("retourne 404 pour un pack inexistant", async () => {
      const ctx = makeAuthCtx(42);
      (ctx.db.execute as any).mockReset().mockResolvedValue([[]]);

      const app = fastify();
      registerAvatarPackRoutes(app, ctx);

      const res = await app.inject({
        method: "GET",
        url: "/avatar-packs/unknown",
      });
      expect(res.statusCode).toBe(404);
    });
  });

  describe("GET /avatar-packs/user/:userId", () => {
    it("retourne les packs possédés par l'utilisateur", async () => {
      const ctx = makeAuthCtx(42);
      (ctx.db.execute as any)
        .mockReset()
        .mockResolvedValueOnce([
          [{ pack_id: "cool", purchased_at: "2025-01-01T00:00:00Z" }],
        ])
        .mockResolvedValueOnce([
          [
            {
              id: 1,
              pack_id: "cool",
              name: "Cool",
              description: null,
              price: 4.99,
              folder_path: "/cool",
              avatar_count: 19,
              is_active: 1,
            },
          ],
        ]);

      const app = fastify();
      registerAvatarPackRoutes(app, ctx);

      const res = await app.inject({
        method: "GET",
        url: "/avatar-packs/user/42",
      });
      expect(res.statusCode).toBe(200);
      const body = JSON.parse(res.body);
      expect(body.ownedPacks).toBeDefined();
    });

    it("retourne 403 si userId ne correspond pas", async () => {
      const app = fastify();
      registerAvatarPackRoutes(app, makeAuthCtx(42));

      const res = await app.inject({
        method: "GET",
        url: "/avatar-packs/user/99",
      });
      expect(res.statusCode).toBe(403);
    });
  });

  describe("POST /avatar-packs/purchase/:userId", () => {
    it("refuse sans transactionId", async () => {
      const ctx = makeAuthCtx(42);
      (ctx.db.execute as any).mockReset().mockResolvedValueOnce([
        [
          {
            id: 1,
            pack_id: "cool",
            name: "Cool",
            description: null,
            price: 4.99,
            folder_path: "/cool",
            avatar_count: 19,
            is_active: 1,
          },
        ],
      ]);

      const app = fastify();
      registerAvatarPackRoutes(app, ctx);

      const res = await app.inject({
        method: "POST",
        url: "/avatar-packs/purchase/42",
        payload: { packId: "cool" },
      });
      expect(res.statusCode).toBe(400);
      expect(JSON.parse(res.body).error).toContain("transactionId");
    });

    it("refuse si userId ne correspond pas", async () => {
      const app = fastify();
      registerAvatarPackRoutes(app, makeAuthCtx(42));

      const res = await app.inject({
        method: "POST",
        url: "/avatar-packs/purchase/99",
        payload: { packId: "cool", transactionId: "txn_123" },
      });
      expect(res.statusCode).toBe(403);
    });

    it("refuse un pack inexistant", async () => {
      const ctx = makeAuthCtx(42);
      (ctx.db.execute as any).mockReset().mockResolvedValue([[]]);

      const app = fastify();
      registerAvatarPackRoutes(app, ctx);

      const res = await app.inject({
        method: "POST",
        url: "/avatar-packs/purchase/42",
        payload: { packId: "unknown", transactionId: "txn_123" },
      });
      expect(res.statusCode).toBe(404);
    });
  });
});
