import { render, screen } from '@testing-library/react';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import type { WorkSession } from '@solelog/shared';
import Live from './Live';
import { apiFetch } from '../lib/api';

vi.mock('../lib/api', () => ({
  apiFetch: vi.fn(),
}));

const mockApiFetch = vi.mocked(apiFetch);

function makeSession(over: Partial<WorkSession>): WorkSession {
  return {
    id: 1,
    user_id: 'u1',
    activity_id: 10,
    activity_name: 'Frezen',
    user_name: 'Jan',
    insole_type: 'Kurk',
    pair_count: 4,
    start_time: new Date(Date.now() - 65_000).toISOString(),
    end_time: null,
    duration_seconds: null,
    paused_seconds: 0,
    paused_at: null,
    status: 'active',
    source: 'app',
    notes: null,
    created_at: new Date().toISOString(),
    ...over,
  };
}

function renderLive() {
  const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } } });
  return render(
    <QueryClientProvider client={queryClient}>
      <Live />
    </QueryClientProvider>,
  );
}

describe('Live', () => {
  beforeEach(() => {
    mockApiFetch.mockReset();
  });

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

  it('renders a card per active session with header count', async () => {
    mockApiFetch.mockResolvedValue([
      makeSession({ id: 1, user_name: 'Jan', activity_name: 'Frezen', insole_type: 'Kurk' }),
      makeSession({ id: 2, user_name: 'Piet', activity_name: 'Lijmen', insole_type: 'Berk' }),
    ]);

    renderLive();

    expect(await screen.findByText('Actief nu (2)')).toBeInTheDocument();
    expect(screen.getByText('Jan')).toBeInTheDocument();
    expect(screen.getByText('Frezen')).toBeInTheDocument();
    expect(screen.getByText('Piet')).toBeInTheDocument();
    expect(screen.getByText('Lijmen')).toBeInTheDocument();
  });

  it('shows the empty state when nobody is working', async () => {
    mockApiFetch.mockResolvedValue([]);

    renderLive();

    expect(await screen.findByText('Niemand is nu aan het werk.')).toBeInTheDocument();
    expect(screen.getByText('Actief nu (0)')).toBeInTheDocument();
  });

  it('shows a Gepauzeerd badge with a frozen worked timer when paused_at is set', async () => {
    vi.useFakeTimers();
    const start = Date.now() - 100_000;
    const pausedAt = Date.now() - 40_000; // paused 40s ago
    mockApiFetch.mockResolvedValue([
      makeSession({
        id: 1,
        user_name: 'Jan',
        start_time: new Date(start).toISOString(),
        paused_at: new Date(pausedAt).toISOString(),
        paused_seconds: 10,
      }),
    ]);

    renderLive();

    // The fake clock needs to advance for react-query's async resolution.
    await vi.advanceTimersByTimeAsync(0);
    expect(screen.getByText('Gepauzeerd')).toBeInTheDocument();

    // worked = (paused_at - start)/1000 - paused_seconds = 60 - 10 = 50s = 00:00:50
    const frozen = screen.getByText('00:00:50');
    expect(frozen).toBeInTheDocument();

    // Advance the 1s tick: the worked timer must stay frozen (does not count up).
    await vi.advanceTimersByTimeAsync(3000);
    expect(screen.getByText('00:00:50')).toBeInTheDocument();
  });

  it('shows the paused total when paused_seconds > 0', async () => {
    mockApiFetch.mockResolvedValue([
      makeSession({
        id: 1,
        user_name: 'Jan',
        paused_seconds: 125,
        paused_at: new Date().toISOString(),
      }),
    ]);

    renderLive();

    // 125s = 00:02:05
    expect(await screen.findByText('Pauze 00:02:05')).toBeInTheDocument();
  });

  it('keeps the timer counting (no Gepauzeerd badge) when not paused', async () => {
    vi.useFakeTimers();
    mockApiFetch.mockResolvedValue([
      makeSession({
        id: 1,
        user_name: 'Jan',
        start_time: new Date(Date.now() - 10_000).toISOString(),
        paused_at: null,
        paused_seconds: 0,
      }),
    ]);

    renderLive();

    await vi.advanceTimersByTimeAsync(0);
    expect(screen.queryByText('Gepauzeerd')).not.toBeInTheDocument();
    expect(screen.getByText('00:00:10')).toBeInTheDocument();

    await vi.advanceTimersByTimeAsync(2000);
    expect(screen.getByText('00:00:12')).toBeInTheDocument();
  });
});
