import { render, screen, fireEvent } from '@testing-library/react';
import { describe, it, expect, vi } from 'vitest';

import { StepContent, Stepper, StepperNavigation } from './stepper';

const steps = [
  { id: 'step-1', label: 'Step One' },
  { id: 'step-2', label: 'Step Two' },
  { id: 'step-3', label: 'Step Three' },
];

describe('Stepper', () => {
  it('renders correct number of step labels', () => {
    render(
      <Stepper steps={steps} currentStep={0} onStepChange={vi.fn()}>
        <div>Content</div>
      </Stepper>,
    );
    expect(screen.getByText('Step One')).toBeInTheDocument();
    expect(screen.getByText('Step Two')).toBeInTheDocument();
    expect(screen.getByText('Step Three')).toBeInTheDocument();
  });

  it('marks current step with aria-current', () => {
    const { container } = render(
      <Stepper steps={steps} currentStep={1} onStepChange={vi.fn()}>
        <div>Content</div>
      </Stepper>,
    );
    const currentStep = container.querySelector('[aria-selected="true"]');
    expect(currentStep).toBeInTheDocument();
    expect(currentStep?.textContent).toBe('2');
  });

  it('shows checkmark for completed steps', () => {
    const { container } = render(
      <Stepper steps={steps} currentStep={2} onStepChange={vi.fn()}>
        <div>Content</div>
      </Stepper>,
    );
    // Steps 0 and 1 are completed — should show check icons
    const checkmarks = container.querySelectorAll('.animate-checkmark');
    expect(checkmarks.length).toBe(2);
  });

  it('renders children', () => {
    render(
      <Stepper steps={steps} currentStep={0} onStepChange={vi.fn()}>
        <div data-testid="child">Child Content</div>
      </Stepper>,
    );
    expect(screen.getByTestId('child')).toBeInTheDocument();
  });

  // ============================================
  // WCAG 2.1 AA 2.1.2: Keyboard Accessible Tests
  // ============================================

  describe('keyboard accessibility (WCAG 2.1 AA 2.1.2)', () => {
    it('renders tablist role on step indicator container', () => {
      render(
        <Stepper steps={steps} currentStep={0} onStepChange={vi.fn()}>
          <div>Content</div>
        </Stepper>,
      );

      const tablist = screen.getByRole('tablist');
      expect(tablist).toBeInTheDocument();
    });

    it('renders tab role on each step button', () => {
      render(
        <Stepper steps={steps} currentStep={0} onStepChange={vi.fn()}>
          <div>Content</div>
        </Stepper>,
      );

      const tabs = screen.getAllByRole('tab');
      expect(tabs).toHaveLength(3);
    });

    it('sets aria-selected=true on current step', () => {
      render(
        <Stepper steps={steps} currentStep={1} onStepChange={vi.fn()}>
          <div>Content</div>
        </Stepper>,
      );

      const tabs = screen.getAllByRole('tab');
      expect(tabs[1]).toHaveAttribute('aria-selected', 'true');
    });

    it('sets aria-selected=false on non-current steps', () => {
      render(
        <Stepper steps={steps} currentStep={1} onStepChange={vi.fn()}>
          <div>Content</div>
        </Stepper>,
      );

      const tabs = screen.getAllByRole('tab');
      expect(tabs[0]).toHaveAttribute('aria-selected', 'false');
      expect(tabs[2]).toHaveAttribute('aria-selected', 'false');
    });

    it('implements roving tabindex pattern - current step has tabindex=0', () => {
      render(
        <Stepper steps={steps} currentStep={1} onStepChange={vi.fn()}>
          <div>Content</div>
        </Stepper>,
      );

      const tabs = screen.getAllByRole('tab');
      expect(tabs[1]).toHaveAttribute('tabindex', '0');
    });

    it('implements roving tabindex pattern - non-current steps have tabindex=-1', () => {
      render(
        <Stepper steps={steps} currentStep={1} onStepChange={vi.fn()}>
          <div>Content</div>
        </Stepper>,
      );

      const tabs = screen.getAllByRole('tab');
      expect(tabs[0]).toHaveAttribute('tabindex', '-1');
      expect(tabs[2]).toHaveAttribute('tabindex', '-1');
    });

    it('renders tabpanel role on step content', () => {
      render(
        <Stepper steps={steps} currentStep={0} onStepChange={vi.fn()}>
          <div>Test Content</div>
        </Stepper>,
      );

      const tabpanel = screen.getByRole('tabpanel');
      expect(tabpanel).toBeInTheDocument();
    });

    it('navigates to next step with ArrowRight key', () => {
      const onStepChange = vi.fn();
      render(
        <Stepper steps={steps} currentStep={0} onStepChange={onStepChange}>
          <div>Content</div>
        </Stepper>,
      );

      const tablist = screen.getByRole('tablist');
      fireEvent.keyDown(tablist, { key: 'ArrowRight' });

      expect(onStepChange).toHaveBeenCalledWith(1);
    });

    it('navigates to next step with ArrowDown key', () => {
      const onStepChange = vi.fn();
      render(
        <Stepper steps={steps} currentStep={0} onStepChange={onStepChange}>
          <div>Content</div>
        </Stepper>,
      );

      const tablist = screen.getByRole('tablist');
      fireEvent.keyDown(tablist, { key: 'ArrowDown' });

      expect(onStepChange).toHaveBeenCalledWith(1);
    });

    it('navigates to previous step with ArrowLeft key', () => {
      const onStepChange = vi.fn();
      render(
        <Stepper steps={steps} currentStep={1} onStepChange={onStepChange}>
          <div>Content</div>
        </Stepper>,
      );

      const tablist = screen.getByRole('tablist');
      fireEvent.keyDown(tablist, { key: 'ArrowLeft' });

      expect(onStepChange).toHaveBeenCalledWith(0);
    });

    it('navigates to previous step with ArrowUp key', () => {
      const onStepChange = vi.fn();
      render(
        <Stepper steps={steps} currentStep={1} onStepChange={onStepChange}>
          <div>Content</div>
        </Stepper>,
      );

      const tablist = screen.getByRole('tablist');
      fireEvent.keyDown(tablist, { key: 'ArrowUp' });

      expect(onStepChange).toHaveBeenCalledWith(0);
    });

    it('navigates to first step with Home key', () => {
      const onStepChange = vi.fn();
      render(
        <Stepper steps={steps} currentStep={2} onStepChange={onStepChange}>
          <div>Content</div>
        </Stepper>,
      );

      const tablist = screen.getByRole('tablist');
      fireEvent.keyDown(tablist, { key: 'Home' });

      expect(onStepChange).toHaveBeenCalledWith(0);
    });

    it('navigates to last step with End key', () => {
      const onStepChange = vi.fn();
      render(
        <Stepper steps={steps} currentStep={0} onStepChange={onStepChange}>
          <div>Content</div>
        </Stepper>,
      );

      const tablist = screen.getByRole('tablist');
      fireEvent.keyDown(tablist, { key: 'End' });

      expect(onStepChange).toHaveBeenCalledWith(2);
    });

    it('does not navigate forward when on last step with ArrowRight', () => {
      const onStepChange = vi.fn();
      render(
        <Stepper steps={steps} currentStep={2} onStepChange={onStepChange}>
          <div>Content</div>
        </Stepper>,
      );

      const tablist = screen.getByRole('tablist');
      fireEvent.keyDown(tablist, { key: 'ArrowRight' });

      expect(onStepChange).not.toHaveBeenCalled();
    });

    it('does not navigate backward when on first step with ArrowLeft', () => {
      const onStepChange = vi.fn();
      render(
        <Stepper steps={steps} currentStep={0} onStepChange={onStepChange}>
          <div>Content</div>
        </Stepper>,
      );

      const tablist = screen.getByRole('tablist');
      fireEvent.keyDown(tablist, { key: 'ArrowLeft' });

      expect(onStepChange).not.toHaveBeenCalled();
    });

    it('can navigate to step by clicking step button', () => {
      const onStepChange = vi.fn();
      render(
        <Stepper steps={steps} currentStep={0} onStepChange={onStepChange}>
          <div>Content</div>
        </Stepper>,
      );

      const tabs = screen.getAllByRole('tab');
      fireEvent.click(tabs[2]);

      expect(onStepChange).toHaveBeenCalledWith(2);
    });
  });
});

describe('StepContent', () => {
  it('renders content only when step matches currentStep', () => {
    const { rerender } = render(
      <StepContent step={0} currentStep={0}>
        <div data-testid="content">Step 0 Content</div>
      </StepContent>,
    );
    expect(screen.getByTestId('content')).toBeInTheDocument();

    rerender(
      <StepContent step={0} currentStep={1}>
        <div data-testid="content">Step 0 Content</div>
      </StepContent>,
    );
    expect(screen.queryByTestId('content')).not.toBeInTheDocument();
  });
});

describe('StepperNavigation', () => {
  it('disables back button on first step', () => {
    render(<StepperNavigation currentStep={0} totalSteps={3} onBack={vi.fn()} onNext={vi.fn()} />);
    // Back button should not be present on first step
    expect(screen.queryByText('Back')).not.toBeInTheDocument();
  });

  it('shows back button on non-first steps', () => {
    render(<StepperNavigation currentStep={1} totalSteps={3} onBack={vi.fn()} onNext={vi.fn()} />);
    expect(screen.getByText('Back')).toBeInTheDocument();
  });

  it('shows Finish label on last step', () => {
    render(<StepperNavigation currentStep={2} totalSteps={3} onBack={vi.fn()} onNext={vi.fn()} />);
    expect(screen.getByText('Finish')).toBeInTheDocument();
  });

  it('shows Next label on non-last steps', () => {
    render(<StepperNavigation currentStep={0} totalSteps={3} onBack={vi.fn()} onNext={vi.fn()} />);
    expect(screen.getByText('Next')).toBeInTheDocument();
  });

  it('calls onNext when Next is clicked', () => {
    const onNext = vi.fn();
    render(<StepperNavigation currentStep={0} totalSteps={3} onBack={vi.fn()} onNext={onNext} />);
    fireEvent.click(screen.getByText('Next'));
    expect(onNext).toHaveBeenCalledTimes(1);
  });

  it('calls onBack when Back is clicked', () => {
    const onBack = vi.fn();
    render(<StepperNavigation currentStep={1} totalSteps={3} onBack={onBack} onNext={vi.fn()} />);
    fireEvent.click(screen.getByText('Back'));
    expect(onBack).toHaveBeenCalledTimes(1);
  });

  it('shows Skip button when onSkip is provided', () => {
    const onSkip = vi.fn();
    render(
      <StepperNavigation
        currentStep={0}
        totalSteps={3}
        onBack={vi.fn()}
        onNext={vi.fn()}
        onSkip={onSkip}
      />,
    );
    expect(screen.getByText('Skip')).toBeInTheDocument();
    fireEvent.click(screen.getByText('Skip'));
    expect(onSkip).toHaveBeenCalledTimes(1);
  });

  it('uses custom finish label', () => {
    render(
      <StepperNavigation
        currentStep={2}
        totalSteps={3}
        onBack={vi.fn()}
        onNext={vi.fn()}
        finishLabel="Get Started"
      />,
    );
    expect(screen.getByText('Get Started')).toBeInTheDocument();
  });
});
