import { fireEvent, render } from '@testing-library/react';
import React from 'react';
import { BrowserRouter as Router } from 'react-router-dom';
import { describe, expect, it, vi } from 'vitest';
import { ButtonContext } from '../Button.model';
import { TextButton } from './TextButton';

describe('TextButton', () => {
  describe('TextContextButton', () => {
    it('renders the component without crashing', () => {
      const { container } = render(<TextButton />);

      expect(container.querySelector('button')).toBeInTheDocument();
    });

    it('raises the onButtonClicked event', () => {
      const spy = vi.fn();
      const { container } = render(<TextButton onButtonClicked={spy} />);

      const button = container.querySelector('button')!;
      fireEvent.click(button);

      expect(spy).toHaveBeenCalledTimes(1);
    });

    it('creates a class based off of the className prop', () => {
      const mockClassName = 'test-class';
      const { container } = render(<TextButton className={mockClassName} />);

      const button = container.querySelector('button')!;

      expect(button.classList.contains(mockClassName)).toBe(true);
    });

    it(`button 'type' must be 'button' by default`, () => {
      const { container } = render(<TextButton />);

      const button = container.querySelector('button')!;

      expect(button.type).toBe('button');
    });

    it('accepts type html attribute and width/height styles', () => {
      const mockType = 'submit';
      const mockHeight = '75px';
      const mockWidth = '80px';

      const { container, rerender } = render(<TextButton />);

      let button = container.querySelector('button')!;

      expect(button.type).toBe('button');
      expect(button.style.height).toBe('');
      expect(button.style.width).toBe('');

      rerender(
        <TextButton type={mockType} height={mockHeight} width={mockWidth} />,
      );

      button = container.querySelector('button')!;

      expect(button.type).toBe(mockType);
      expect(button.style.height).toBe(mockHeight);
      expect(button.style.width).toBe(mockWidth);
    });

    it('allows the button to be enabled by default', () => {
      const spy = vi.fn();
      const { container } = render(<TextButton onButtonClicked={spy} />);

      const button = container.querySelector('button')!;

      fireEvent.click(button);

      expect(button.disabled).toBe(false);
      expect(spy).toHaveBeenCalledTimes(1);
    });

    it('allows button to be disabled', () => {
      const spy = vi.fn();
      const { container } = render(
        <TextButton disabled={true} onButtonClicked={spy} />,
      );

      const button = container.querySelector('button')!;

      fireEvent.click(button);

      expect(button.disabled).toBe(true);
      expect(spy).not.toHaveBeenCalled();
    });

    it('default should have a context class', () => {
      const { container } = render(<TextButton />);

      const button = container.querySelector('button')!;

      expect(button.classList.contains('context')).toBe(true);
    });

    it('context button type should have a context class', () => {
      const { container } = render(
        <TextButton buttonContext={ButtonContext.Context} />,
      );

      const button = container.querySelector('button')!;

      expect(button.classList.contains('context')).toBe(true);
    });

    it('active button type should have a active class', () => {
      const { container } = render(
        <TextButton buttonContext={ButtonContext.Active} />,
      );

      const button = container.querySelector('button')!;

      expect(button.classList.contains('active')).toBe(true);
    });

    it(`renders value from 'text' prop`, () => {
      const mockText = 'mock-text';

      const { container } = render(<TextButton text={mockText} />);

      const button = container.querySelector('button')!;

      expect(button.textContent).toBe(mockText);
    });

    it(`defaults to an empty string is 'text' prop is not set`, () => {
      const { container } = render(<TextButton />);

      const button = container.querySelector('button')!;

      expect(button.textContent).toBe('');
    });
  });

  describe('TextNavigationButton', () => {
    it('renders the component without crashing', () => {
      const { container } = render(
        <Router>
          <TextButton path={'/'} />
        </Router>,
      );
      expect(container.querySelector('a')).toBeInTheDocument();
    });

    it('renders as a navigation button when path prop is defined', () => {
      const mockPath = '/home';
      const { container } = render(
        <Router>
          <TextButton path={mockPath} />
        </Router>,
      );
      const link = container.querySelector('a')!;
      expect(link).toBeInTheDocument();
      expect(link.getAttribute('href')).toBe(mockPath);
    });

    it('does not open link in new tab by default', () => {
      const mockPath = '/home';
      const { container } = render(
        <Router>
          <TextButton path={mockPath} />
        </Router>,
      );
      const link = container.querySelector('a')!;
      expect(link.getAttribute('target')).toBeNull();
    });

    it('opens link in new tab when openInNewTab prop set to true', () => {
      const mockPath = '/home';
      const { container } = render(
        <Router>
          <TextButton path={mockPath} openInNewTab={true} />
        </Router>,
      );
      const link = container.querySelector('a')!;
      expect(link.getAttribute('target')).toBe('_blank');
    });

    it('creates a class based on the className prop', () => {
      const mockClassName = 'test-class';
      const { container } = render(
        <Router>
          <TextButton path={'/test'} className={mockClassName} />
        </Router>,
      );
      const link = container.querySelector('a')!;
      expect(link.classList.contains(mockClassName)).toBe(true);
    });

    it('accepts width and height styles', () => {
      const mockHeight = '75px';
      const mockWidth = '80px';
      const { container } = render(
        <Router>
          <TextButton path={'/test'} width={mockWidth} height={mockHeight} />
        </Router>,
      );
      const link = container.querySelector('a')!;

      expect(link.style.height).toBe(mockHeight);
      expect(link.style.width).toBe(mockWidth);
    });

    it('allows the link to be enabled by default', () => {
      const { container } = render(
        <Router>
          <TextButton path={'/test'} />
        </Router>,
      );

      const link = container.querySelector('a')!;

      expect(link.classList.contains('disabled')).toBe(false);
    });

    it('allows the button to be disabled', () => {
      const { container } = render(
        <Router>
          <TextButton path={'/test'} disabled={true} />
        </Router>,
      );
      const link = container.querySelector('a')!;
      expect(link.classList.contains('disabled')).toBe(true);
    });

    it('adds `navigation` class for link buttons', () => {
      const { container } = render(
        <Router>
          <TextButton path={'/test'} />
        </Router>,
      );
      const link = container.querySelector('a')!;
      expect(link.classList.contains('navigation')).toBe(true);
    });
  });
});
