import { act, render, screen } from '@testing-library/react';
import { ThemeProvider } from '../../theme';

// next-intl mocked so the locale is `en` and the countdown formats with ASCII digits we can assert on.
jest.mock('next-intl', () => ({ useLocale: () => 'en' }));

import CountdownTimer, { CountdownTimerProps } from './CountdownTimer';

const deadlineInSeconds = (seconds: number) => new Date(Date.now() + seconds * 1000).toISOString();

function renderTimer(props: CountdownTimerProps) {
  return render(
    <ThemeProvider>
      <CountdownTimer {...props} />
    </ThemeProvider>,
  );
}

describe('<CountdownTimer/> component', () => {
  beforeEach(() => {
    jest.useFakeTimers();
    jest.setSystemTime(new Date('2026-07-09T10:00:00.000Z'));
  });

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

  it('renders MM:SS remaining for a sub-hour deadline', () => {
    renderTimer({ deadlineIso: deadlineInSeconds(90), elapsedText: 'time up' });
    expect(screen.getByText('01:30')).toBeInTheDocument();
  });

  it('renders HH:MM:SS for a multi-hour deadline', () => {
    renderTimer({ deadlineIso: deadlineInSeconds(3661), elapsedText: 'time up' });
    expect(screen.getByText('01:01:01')).toBeInTheDocument();
  });

  it('ticks down each second without lifting state to the page', () => {
    renderTimer({ deadlineIso: deadlineInSeconds(90), elapsedText: 'time up' });
    act(() => {
      jest.advanceTimersByTime(1000);
    });
    expect(screen.getByText('01:29')).toBeInTheDocument();
  });

  it('shows the elapsed text and fires onElapsed exactly once at zero', () => {
    const onElapsed = jest.fn();
    renderTimer({ deadlineIso: deadlineInSeconds(2), elapsedText: 'time up', onElapsed });
    act(() => {
      jest.advanceTimersByTime(3000);
    });
    expect(screen.getByText('time up')).toBeInTheDocument();
    expect(onElapsed).toHaveBeenCalledTimes(1);
  });

  it('renders the humanized coarse label above the coarse threshold when coarseLabel is supplied', () => {
    renderTimer({
      deadlineIso: deadlineInSeconds(25 * 60),
      elapsedText: 'time up',
      coarseLabel: (minutes) => `${minutes} min left`,
    });
    expect(screen.getByText('25 min left')).toBeInTheDocument();
    expect(screen.queryByText(/^\d{2}:\d{2}$/)).not.toBeInTheDocument();
  });

  it('falls back to the ticking clock when coarseLabel is not supplied, even above the threshold', () => {
    renderTimer({ deadlineIso: deadlineInSeconds(25 * 60), elapsedText: 'time up' });
    expect(screen.getByText('25:00')).toBeInTheDocument();
  });

  it('renders a determinate progress ring when windowStart is supplied', () => {
    renderTimer({
      deadlineIso: deadlineInSeconds(100),
      windowStart: new Date(Date.now() - 100 * 1000).toISOString(),
      elapsedText: 'time up',
    });
    const ring = screen.getByRole('progressbar');
    expect(ring).toHaveAttribute('aria-valuenow', '50');
  });

  it('omits the progress ring when windowStart is not supplied', () => {
    renderTimer({ deadlineIso: deadlineInSeconds(90), elapsedText: 'time up' });
    expect(screen.queryByRole('progressbar')).not.toBeInTheDocument();
  });
});
