import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import { render, screen, waitFor } from '@testing-library/react';
import { PlaybackDashboard } from './PlaybackDashboard';
import { getPlaybackDashboard } from '../services/playbackAnalyticsService';

// Mock the service
vi.mock('../services/playbackAnalyticsService', () => ({
  getPlaybackDashboard: vi.fn(),
}));

// Mock the chart components
vi.mock('@/components/charts/LineChart', () => ({
  LineChart: ({ data }: { data: any[] }) => (
    <div data-testid="line-chart">
      {data.length > 0 ? `Chart with ${data.length} points` : 'Empty chart'}
    </div>
  ),
  LineChartData: {},
}));

// Mock UI components
vi.mock('@/components/ui/card', () => ({
  Card: ({ children }: { children: React.ReactNode }) => (
    <div data-testid="card">{children}</div>
  ),
  CardContent: ({ children }: { children: React.ReactNode }) => (
    <div data-testid="card-content">{children}</div>
  ),
  CardHeader: ({ children }: { children: React.ReactNode }) => (
    <div data-testid="card-header">{children}</div>
  ),
  CardTitle: ({ children }: { children: React.ReactNode }) => (
    <h3 data-testid="card-title">{children}</h3>
  ),
  CardDescription: ({ children }: { children: React.ReactNode }) => (
    <p data-testid="card-description">{children}</p>
  ),
}));

vi.mock('@/components/ui/loading-spinner', () => ({
  LoadingSpinner: () => <div data-testid="loading-spinner">Loading...</div>,
}));

vi.mock('@/components/ui/badge', () => ({
  Badge: ({ children }: { children: React.ReactNode }) => (
    <span data-testid="badge">{children}</span>
  ),
}));

vi.mock('lucide-react', () => ({
  TrendingUp: () => <span data-testid="trending-up">↑</span>,
  TrendingDown: () => <span data-testid="trending-down">↓</span>,
  Minus: () => <span data-testid="minus">-</span>,
}));

const mockGetPlaybackDashboard = vi.mocked(getPlaybackDashboard);

const mockDashboardData = {
  stats: {
    total_sessions: 100,
    total_play_time: 36000,
    average_play_time: 360,
    total_pauses: 50,
    average_pauses: 0.5,
    total_seeks: 30,
    average_seeks: 0.3,
    average_completion: 75.5,
    completion_rate: 60.0,
  },
  trends: {
    play_time_trend: 10.5,
    completion_trend: -5.2,
    sessions_trend: 15.0,
    average_play_time: 380,
    average_completion: 70.0,
    total_sessions_7days: 25,
    total_sessions_30days: 100,
  },
  time_series: [
    {
      date: '2024-01-01',
      sessions: 5,
      total_play_time: 1800,
      average_play_time: 360,
      average_completion: 75.0,
    },
    {
      date: '2024-01-02',
      sessions: 8,
      total_play_time: 2880,
      average_play_time: 360,
      average_completion: 80.0,
    },
  ],
};

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

  afterEach(() => {
    vi.clearAllMocks();
  });

  it('should render loading state initially', () => {
    mockGetPlaybackDashboard.mockImplementation(
      () => new Promise(() => {}), // Never resolves
    );

    render(<PlaybackDashboard trackId={123} />);

    expect(screen.getByTestId('loading-spinner')).toBeInTheDocument();
    expect(
      screen.getByText("Dashboard d'analytics de lecture"),
    ).toBeInTheDocument();
  });

  it('should render dashboard data when loaded', async () => {
    mockGetPlaybackDashboard.mockResolvedValue(mockDashboardData);

    render(<PlaybackDashboard trackId={123} />);

    await waitFor(() => {
      expect(screen.getByText('Statistiques générales')).toBeInTheDocument();
    });

    // Check for stats - use getAllByText for values that might appear multiple times
    const totalSessions = screen.getAllByText('100');
    expect(totalSessions.length).toBeGreaterThan(0);

    // total_play_time: 36000 seconds = 10 hours
    expect(screen.getByText('10h 0min')).toBeInTheDocument();

    // average_play_time: 360 seconds = 6 minutes
    expect(screen.getByText('6m 0s')).toBeInTheDocument();

    const completionValues = screen.getAllByText('75.5%');
    expect(completionValues.length).toBeGreaterThan(0);
  });

  it('should render trends with correct icons', async () => {
    mockGetPlaybackDashboard.mockResolvedValue(mockDashboardData);

    render(<PlaybackDashboard trackId={123} />);

    await waitFor(() => {
      expect(
        screen.getByText('Tendances (7 derniers jours)'),
      ).toBeInTheDocument();
    });

    // Check for trend indicators - use getAllByText since "Taux de complétion" appears multiple times
    const sessionsElements = screen.getAllByText('Sessions');
    expect(sessionsElements.length).toBeGreaterThan(0);

    const playTimeElements = screen.getAllByText('Temps de lecture');
    expect(playTimeElements.length).toBeGreaterThan(0);

    const completionElements = screen.getAllByText('Taux de complétion');
    expect(completionElements.length).toBeGreaterThan(0);
  });

  it('should render charts when time series data is available', async () => {
    mockGetPlaybackDashboard.mockResolvedValue(mockDashboardData);

    render(<PlaybackDashboard trackId={123} />);

    await waitFor(() => {
      expect(screen.getByText('Évolution des sessions')).toBeInTheDocument();
    });

    const charts = screen.getAllByTestId('line-chart');
    expect(charts.length).toBeGreaterThan(0);
  });

  it('should render error message when API call fails', async () => {
    const errorMessage = 'Track not found: 123';
    mockGetPlaybackDashboard.mockRejectedValue(new Error(errorMessage));

    render(<PlaybackDashboard trackId={123} />);

    await waitFor(() => {
      expect(screen.getByText(errorMessage)).toBeInTheDocument();
    });
  });

  it('should render empty state when no data', async () => {
    const emptyData = {
      stats: {
        total_sessions: 0,
        total_play_time: 0,
        average_play_time: 0,
        total_pauses: 0,
        average_pauses: 0,
        total_seeks: 0,
        average_seeks: 0,
        average_completion: 0,
        completion_rate: 0,
      },
      trends: {
        play_time_trend: 0,
        completion_trend: 0,
        sessions_trend: 0,
        average_play_time: 0,
        average_completion: 0,
        total_sessions_7days: 0,
        total_sessions_30days: 0,
      },
      time_series: [],
    };

    mockGetPlaybackDashboard.mockResolvedValue(emptyData);

    render(<PlaybackDashboard trackId={123} />);

    await waitFor(() => {
      expect(
        screen.getByText(/Aucune session de lecture enregistrée/),
      ).toBeInTheDocument();
    });
  });

  it('should reload dashboard when trackId changes', async () => {
    mockGetPlaybackDashboard.mockResolvedValue(mockDashboardData);

    const { rerender } = render(<PlaybackDashboard trackId={123} />);

    await waitFor(() => {
      expect(mockGetPlaybackDashboard).toHaveBeenCalledWith(123);
    });

    mockGetPlaybackDashboard.mockClear();
    mockGetPlaybackDashboard.mockResolvedValue(mockDashboardData);

    rerender(<PlaybackDashboard trackId={456} />);

    await waitFor(() => {
      expect(mockGetPlaybackDashboard).toHaveBeenCalledWith(456);
    });
  });

  it('should format time correctly', async () => {
    const dataWithDifferentTimes = {
      ...mockDashboardData,
      stats: {
        ...mockDashboardData.stats,
        total_play_time: 3661, // 1h 1min 1s
        average_play_time: 45, // 45s
      },
    };

    mockGetPlaybackDashboard.mockResolvedValue(dataWithDifferentTimes);

    render(<PlaybackDashboard trackId={123} />);

    await waitFor(() => {
      expect(screen.getByText('1h 1min')).toBeInTheDocument(); // total_play_time
      expect(screen.getByText('45s')).toBeInTheDocument(); // average_play_time
    });
  });

  it('should display detailed statistics', async () => {
    mockGetPlaybackDashboard.mockResolvedValue(mockDashboardData);

    render(<PlaybackDashboard trackId={123} />);

    await waitFor(() => {
      expect(screen.getByText('Statistiques détaillées')).toBeInTheDocument();
    });

    expect(screen.getByText('50')).toBeInTheDocument(); // total_pauses
    expect(screen.getByText('30')).toBeInTheDocument(); // total_seeks
    expect(screen.getByText('60.0%')).toBeInTheDocument(); // completion_rate
  });
});
