import { describe, it, expect, beforeEach, vi } from "vitest";
import { gamificationRouter } from "./gamification.ts";
import * as gamificationService from "../services/gamificationService.ts";

// Mock the gamification service
vi.mock("../services/gamificationService", () => ({
  getPlayerStreak: vi.fn(),
  updateLoginStreak: vi.fn(),
  getPlayerBadges: vi.fn(),
  getAvailableBadges: vi.fn(),
  unlockBadge: vi.fn(),
  getWeeklyChallenges: vi.fn(),
  getPlayerChallenges: vi.fn(),
  updateChallengeProgress: vi.fn(),
  completeChallenge: vi.fn(),
  getPlayerStats: vi.fn(),
}));

describe("gamificationRouter", () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  it("should have getStreak procedure", () => {
    expect(gamificationRouter._def.procedures.getStreak).toBeDefined();
  });

  it("should have updateStreak procedure", () => {
    expect(gamificationRouter._def.procedures.updateStreak).toBeDefined();
  });

  it("should have getPlayerBadges procedure", () => {
    expect(gamificationRouter._def.procedures.getPlayerBadges).toBeDefined();
  });

  it("should have getAvailableBadges procedure", () => {
    expect(gamificationRouter._def.procedures.getAvailableBadges).toBeDefined();
  });

  it("should have unlockBadge procedure", () => {
    expect(gamificationRouter._def.procedures.unlockBadge).toBeDefined();
  });

  it("should have getWeeklyChallenges procedure", () => {
    expect(gamificationRouter._def.procedures.getWeeklyChallenges).toBeDefined();
  });

  it("should have getPlayerChallenges procedure", () => {
    expect(gamificationRouter._def.procedures.getPlayerChallenges).toBeDefined();
  });

  it("should have updateChallengeProgress procedure", () => {
    expect(gamificationRouter._def.procedures.updateChallengeProgress).toBeDefined();
  });

  it("should have completeChallenge procedure", () => {
    expect(gamificationRouter._def.procedures.completeChallenge).toBeDefined();
  });

  it("should have getStats procedure", () => {
    expect(gamificationRouter._def.procedures.getStats).toBeDefined();
  });

  it("getPlayerStreak should return player streak", async () => {
    const mockStreak = {
      playerId: 1,
      currentStreak: 7,
      longestStreak: 30,
      lastLoginDate: new Date(),
      streakBonusMultiplier: 2,
    };

    vi.mocked(gamificationService.getPlayerStreak).mockResolvedValue(mockStreak);

    const result = await gamificationService.getPlayerStreak(1);
    expect(result).toEqual(mockStreak);
    expect(gamificationService.getPlayerStreak).toHaveBeenCalledWith(1);
  });

  it("updateLoginStreak should return updated streak", async () => {
    const mockStreak = {
      playerId: 1,
      currentStreak: 8,
      longestStreak: 30,
      lastLoginDate: new Date(),
      streakBonusMultiplier: 2,
    };

    vi.mocked(gamificationService.updateLoginStreak).mockResolvedValue(mockStreak);

    const result = await gamificationService.updateLoginStreak(1);
    expect(result).toEqual(mockStreak);
    expect(gamificationService.updateLoginStreak).toHaveBeenCalledWith(1);
  });

  it("getPlayerBadges should return player badges", async () => {
    const mockBadges = [
      {
        id: "first_spin",
        name: "First Spin",
        description: "Play your first spin",
        icon: "🎰",
        rarity: "common" as const,
        unlockCondition: "Play 1 game",
        points: 10,
      },
    ];

    vi.mocked(gamificationService.getPlayerBadges).mockResolvedValue(mockBadges);

    const result = await gamificationService.getPlayerBadges(1);
    expect(result).toEqual(mockBadges);
    expect(gamificationService.getPlayerBadges).toHaveBeenCalledWith(1);
  });

  it("getAvailableBadges should return all badges", async () => {
    const mockBadges = [
      {
        id: "first_spin",
        name: "First Spin",
        description: "Play your first spin",
        icon: "🎰",
        rarity: "common" as const,
        unlockCondition: "Play 1 game",
        points: 10,
      },
      {
        id: "big_winner",
        name: "Big Winner",
        description: "Win 50,000 GC total",
        icon: "🏆",
        rarity: "rare" as const,
        unlockCondition: "Win 50,000 GC",
        points: 100,
      },
    ];

    vi.mocked(gamificationService.getAvailableBadges).mockResolvedValue(mockBadges);

    const result = await gamificationService.getAvailableBadges();
    expect(result.length).toBeGreaterThan(0);
    expect(gamificationService.getAvailableBadges).toHaveBeenCalled();
  });

  it("unlockBadge should return success", async () => {
    vi.mocked(gamificationService.unlockBadge).mockResolvedValue(true);

    const result = await gamificationService.unlockBadge(1, "first_spin");
    expect(result).toBe(true);
    expect(gamificationService.unlockBadge).toHaveBeenCalledWith(1, "first_spin");
  });

  it("getWeeklyChallenges should return challenges", async () => {
    const mockChallenges = [
      {
        id: "spin_10",
        name: "Spin Master",
        description: "Complete 10 spins",
        objective: "Complete 10 spins",
        targetValue: 10,
        reward: 500,
        icon: "🎰",
        difficulty: "easy" as const,
        weekStartDate: new Date(),
        weekEndDate: new Date(),
      },
    ];

    vi.mocked(gamificationService.getWeeklyChallenges).mockResolvedValue(mockChallenges);

    const result = await gamificationService.getWeeklyChallenges();
    expect(result.length).toBeGreaterThan(0);
    expect(gamificationService.getWeeklyChallenges).toHaveBeenCalled();
  });

  it("getPlayerChallenges should return player challenges", async () => {
    const mockChallenges = [
      {
        playerId: 1,
        challengeId: "spin_10",
        progress: 5,
        completed: false,
        reward: 500,
      },
    ];

    vi.mocked(gamificationService.getPlayerChallenges).mockResolvedValue(mockChallenges);

    const result = await gamificationService.getPlayerChallenges(1);
    expect(result).toEqual(mockChallenges);
    expect(gamificationService.getPlayerChallenges).toHaveBeenCalledWith(1);
  });

  it("updateChallengeProgress should return updated challenge", async () => {
    const mockChallenge = {
      playerId: 1,
      challengeId: "spin_10",
      progress: 6,
      completed: false,
      reward: 500,
    };

    vi.mocked(gamificationService.updateChallengeProgress).mockResolvedValue(mockChallenge);

    const result = await gamificationService.updateChallengeProgress(1, "spin_10", 1);
    expect(result).toEqual(mockChallenge);
    expect(gamificationService.updateChallengeProgress).toHaveBeenCalledWith(1, "spin_10", 1);
  });

  it("completeChallenge should return reward", async () => {
    vi.mocked(gamificationService.completeChallenge).mockResolvedValue(500);

    const result = await gamificationService.completeChallenge(1, "spin_10");
    expect(result).toBe(500);
    expect(gamificationService.completeChallenge).toHaveBeenCalledWith(1, "spin_10");
  });

  it("getPlayerStats should return stats", async () => {
    const mockStats = {
      totalBadges: 5,
      completedChallenges: 2,
      currentStreak: 7,
      longestStreak: 30,
      streakMultiplier: 2,
      totalBadgePoints: 150,
    };

    vi.mocked(gamificationService.getPlayerStats).mockResolvedValue(mockStats);

    const result = await gamificationService.getPlayerStats(1);
    expect(result).toEqual(mockStats);
    expect(gamificationService.getPlayerStats).toHaveBeenCalledWith(1);
  });
});
