import { describe, it, expect, vi, beforeEach } from "vitest";
import fastify from "fastify";
import { registerChallengePackRoutes } from "../challenge-pack-routes.js";
import { makeCtx } from "./helpers.js";

vi.mock("../../server/admin-service.js", () => ({
  recordAudit: vi.fn(),
}));

vi.mock("../../server/parsers.js", () => ({
  parseLevelPayload: vi.fn((payload: unknown) =>
    payload
      ? {
          grid: [
            [1, 2],
            [3, 0],
          ],
          emptyPos: [1, 1],
        }
      : null,
  ),
}));

const makeAuthCtx = (userId = 42) => {
  const executeFn = vi
    .fn()
    // isChallengePackEnabled
    .mockResolvedValueOnce([[{ config_value: "true" }]])
    // userOwnsChallengePack (status)
    .mockResolvedValueOnce([[]])
    // countPastWeeklyAvatars
    .mockResolvedValueOnce([[{ count: 5 }]])
    // getPastWeeklyAvatars
    .mockResolvedValueOnce([
      [
        { week_key: "2025-W01", avatar_id: 100 },
        { week_key: "2025-W02", avatar_id: 101 },
      ],
    ])
    .mockResolvedValue([{ affectedRows: 1 }]);

  return makeCtx({
    db: { execute: executeFn } as any,
    requireAuth: async (request: any) => {
      request.user = { sub: userId };
    },
  });
};

describe("challenge-pack-routes", () => {
  beforeEach(() => vi.clearAllMocks());

  // ────────────── GET /challenge-pack/status ──────────────

  describe("GET /challenge-pack/status", () => {
    it("retourne le status du challenge pack", async () => {
      const app = fastify();
      registerChallengePackRoutes(app, makeAuthCtx(42));

      const res = await app.inject({
        method: "GET",
        url: "/challenge-pack/status",
      });
      expect(res.statusCode).toBe(200);
      const body = JSON.parse(res.body);
      expect(body.price).toBe(4.99);
      expect(body.enabled).toBe(true);
    });
  });

  // ────────────── POST /challenge-pack/purchase/:userId ──────────────

  describe("POST /challenge-pack/purchase/:userId", () => {
    it("refuse si userId ne correspond pas", async () => {
      const app = fastify();
      registerChallengePackRoutes(app, makeAuthCtx(42));

      const res = await app.inject({
        method: "POST",
        url: "/challenge-pack/purchase/99",
        payload: { transactionId: "txn_123" },
      });
      expect(res.statusCode).toBe(403);
    });

    it("refuse un userId non numérique", async () => {
      const app = fastify();
      registerChallengePackRoutes(app, makeAuthCtx(42));

      const res = await app.inject({
        method: "POST",
        url: "/challenge-pack/purchase/abc",
        payload: { transactionId: "txn_123" },
      });
      expect(res.statusCode).toBe(400);
    });
  });

  // ────────────── GET /challenge-pack/challenges/:userId ──────────────

  describe("GET /challenge-pack/challenges/:userId", () => {
    it("refuse si userId ne correspond pas", async () => {
      const app = fastify();
      registerChallengePackRoutes(app, makeAuthCtx(42));

      const res = await app.inject({
        method: "GET",
        url: "/challenge-pack/challenges/99",
      });
      expect(res.statusCode).toBe(403);
    });

    it("refuse un userId non numérique", async () => {
      const app = fastify();
      registerChallengePackRoutes(app, makeAuthCtx(42));

      const res = await app.inject({
        method: "GET",
        url: "/challenge-pack/challenges/abc",
      });
      expect(res.statusCode).toBe(400);
    });
  });

  // ────────────── GET /challenge-pack/level/:dateKey ──────────────

  describe("GET /challenge-pack/level/:dateKey", () => {
    it("refuse une date invalide", async () => {
      const ctx = makeAuthCtx(42);
      // Override pour userOwnsChallengePack → true
      (ctx.db.execute as any)
        .mockReset()
        .mockResolvedValueOnce([[{ id: 1 }]]) // owns pack
        .mockResolvedValue([[]]);

      const app = fastify();
      registerChallengePackRoutes(app, ctx);

      const res = await app.inject({
        method: "GET",
        url: "/challenge-pack/level/not-a-date",
      });
      expect(res.statusCode).toBe(400);
    });

    it("refuse une date future", async () => {
      const ctx = makeAuthCtx(42);
      (ctx.db.execute as any)
        .mockReset()
        .mockResolvedValueOnce([[{ id: 1 }]]) // owns pack
        .mockResolvedValue([[]]);

      const app = fastify();
      registerChallengePackRoutes(app, ctx);

      const tomorrow = new Date();
      tomorrow.setDate(tomorrow.getDate() + 2);
      const dateKey = tomorrow.toISOString().slice(0, 10);

      const res = await app.inject({
        method: "GET",
        url: `/challenge-pack/level/${dateKey}`,
      });
      expect(res.statusCode).toBe(400);
    });
  });
});
