// src/components/Leaderboard.test.tsx
import React from 'react';
import { render, screen, waitFor } from '@testing-library/react';
import { describe, it, expect, vi, beforeEach, type Mocked } from 'vitest';
import Leaderboard from './Leaderboard';
import * as apiClient from '../services/apiClient';
import { LeaderboardUser } from '../types';

// Mock the apiClient
vi.mock('../services/apiClient'); // This was correct
const mockedApiClient = apiClient as Mocked<typeof apiClient>;

// Mock the logger
vi.mock('../services/logger', () => ({
  logger: {
    error: vi.fn(),
  },
}));

// Mock lucide-react icons to prevent rendering errors in the test environment
vi.mock('lucide-react', () => ({
  Award: () => <div data-testid="award-icon" />,
  Crown: () => <div data-testid="crown-icon" />,
  ShieldAlert: () => <div data-testid="shield-alert-icon" />,
}));

const mockLeaderboardData: LeaderboardUser[] = [
  { user_id: 'user-1', full_name: 'Alice', avatar_url: null, points: 1000, rank: '1' },
  { user_id: 'user-2', full_name: 'Bob', avatar_url: 'http://example.com/bob.jpg', points: 950, rank: '2' },
  { user_id: 'user-3', full_name: 'Charlie', avatar_url: null, points: 900, rank: '3' },
  { user_id: 'user-4', full_name: 'Diana', avatar_url: null, points: 850, rank: '4' },
];

describe('Leaderboard', () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  it('should display a loading message initially', () => {
    // Mock a pending promise that never resolves to keep it in the loading state
    mockedApiClient.fetchLeaderboard.mockReturnValue(new Promise(() => {}));
    render(<Leaderboard />);
    expect(screen.getByText('Loading Leaderboard...')).toBeInTheDocument();
  });

  it('should display an error message if the API call fails', async () => {
    mockedApiClient.fetchLeaderboard.mockResolvedValue(new Response(null, { status: 500 }));
    render(<Leaderboard />);

    await waitFor(() => {
      expect(screen.getByRole('alert')).toBeInTheDocument();
      expect(screen.getByText('Error: Failed to fetch leaderboard data.')).toBeInTheDocument();
    });
  });

  it('should display a message when the leaderboard is empty', async () => {
    mockedApiClient.fetchLeaderboard.mockResolvedValue(new Response(JSON.stringify([])));
    render(<Leaderboard />);

    await waitFor(() => {
      expect(screen.getByText('The leaderboard is currently empty. Be the first to earn points!')).toBeInTheDocument();
    });
  });

  it('should render the leaderboard with user data on successful fetch', async () => {
    mockedApiClient.fetchLeaderboard.mockResolvedValue(new Response(JSON.stringify(mockLeaderboardData)));
    render(<Leaderboard />);

    await waitFor(() => {
      expect(screen.getByRole('heading', { name: 'Top Users' })).toBeInTheDocument();

      // Check for user details
      expect(screen.getByText('Alice')).toBeInTheDocument();
      expect(screen.getByText('1000 pts')).toBeInTheDocument();

      expect(screen.getByText('Bob')).toBeInTheDocument();
      expect(screen.getByText('950 pts')).toBeInTheDocument();

      // Check for correct avatar URLs
      const bobAvatar = screen.getByAltText('Bob') as HTMLImageElement;
      expect(bobAvatar.src).toBe('http://example.com/bob.jpg');

      const aliceAvatar = screen.getByAltText('Alice') as HTMLImageElement;
      expect(aliceAvatar.src).toContain('api.dicebear.com'); // Check for fallback avatar
    });
  });

  it('should render the correct rank icons', async () => {
    mockedApiClient.fetchLeaderboard.mockResolvedValue(new Response(JSON.stringify(mockLeaderboardData)));
    render(<Leaderboard />);

    await waitFor(() => {
      // Rank 1, 2, and 3 should have a crown icon
      const crownIcons = screen.getAllByTestId('crown-icon');
      expect(crownIcons).toHaveLength(3);

      // Rank 4 should display the number
      expect(screen.getByText('4')).toBeInTheDocument();
    });
  });
});