import { render, screen, fireEvent } from '@testing-library/react';
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
import { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator } from './input-otp';
import { OTPInputContext } from 'input-otp';
import React from 'react';

describe('InputOTP', () => {
  // input-otp schedules internal setTimeout(0/10/50) calls on mount that it
  // never cancels on unmount. Under real timers those fire after this file's
  // jsdom environment is torn down, throwing `window is not defined` as an
  // unhandled error in later test files. Fake timers keep them from ever
  // firing for real.
  beforeEach(() => {
    vi.useFakeTimers();
  });

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

  it('renders children correctly', () => {
    render(
      <OTPInputContext.Provider value={{ slots: [{ char: 'A' }] } as any}>
        <InputOTPSlot index={0} />
      </OTPInputContext.Provider>
    );
    expect(screen.getByText('A')).toBeInTheDocument();
  });

  it('renders correctly with different sizes', () => {
    const { rerender, container } = render(
      <OTPInputContext.Provider value={{ slots: [{ char: 'A' }] } as any}>
        <InputOTPSlot index={0} size="sm" />
      </OTPInputContext.Provider>
    );
    expect(container.querySelector('[data-slot="input-otp-slot"]')).toHaveClass('h-8', 'w-8');

    rerender(
      <OTPInputContext.Provider value={{ slots: [{ char: 'A' }] } as any}>
        <InputOTPSlot index={0} size="md" />
      </OTPInputContext.Provider>
    );
    expect(container.querySelector('[data-slot="input-otp-slot"]')).toHaveClass('h-10', 'w-10');

    rerender(
      <OTPInputContext.Provider value={{ slots: [{ char: 'A' }] } as any}>
        <InputOTPSlot index={0} size="lg" />
      </OTPInputContext.Provider>
    );
    expect(container.querySelector('[data-slot="input-otp-slot"]')).toHaveClass('h-12', 'w-12');
  });

  it('renders correctly', () => {
    const { container } = render(
      <InputOTP maxLength={6}>
        <InputOTPGroup>
          <InputOTPSlot index={0} />
          <InputOTPSlot index={1} />
        </InputOTPGroup>
        <InputOTPSeparator />
        <InputOTPGroup>
          <InputOTPSlot index={2} />
          <InputOTPSlot index={3} />
        </InputOTPGroup>
      </InputOTP>
    );
    expect(container.querySelector('[data-slot="input-otp"]')).toBeInTheDocument();
    expect(container.querySelectorAll('[data-slot="input-otp-slot"]')).toHaveLength(4);
    expect(container.querySelector('[data-slot="input-otp-separator"]')).toBeInTheDocument();
  });

  it('updates value on typing', () => {
    render(
      <InputOTP maxLength={4}>
        <InputOTPGroup>
          <InputOTPSlot index={0} />
          <InputOTPSlot index={1} />
          <InputOTPSlot index={2} />
          <InputOTPSlot index={3} />
        </InputOTPGroup>
      </InputOTP>
    );
    const input = screen.getByRole('textbox');
    fireEvent.change(input, { target: { value: '1234' } });
    expect(input).toHaveValue('1234');
  });
});
