import { render, waitFor } from '@testing-library/react';
import React from 'react';
import { MemoryRouter } from 'react-router-dom';
import { describe, expect, it } from 'vitest';
import { TileLarge, TileLargeProps } from './TileLarge';

const mockProps: TileLargeProps = {
  path: 'test-path',
  label: 'test-label',
  icon: '/images/test-icon.png',
  type: 'large',
  subtitle: '48',
};

const MockIcon: React.FC = () => (
  <svg height="100" width="100">
    <circle cx="50" cy="50" r="40" stroke="black" strokeWidth="3" />
  </svg>
);

describe('TileLarge', () => {
  it('renders the component without crashing', () => {
    const { container } = render(
      <MemoryRouter>
        <TileLarge {...mockProps} />
      </MemoryRouter>,
    );
    expect(container).toBeTruthy();
  });

  it('renders the tile label and subtile', () => {
    const { container } = render(
      <MemoryRouter>
        <TileLarge {...mockProps} />
      </MemoryRouter>,
    );

    const label = container.querySelector('.label');
    const subtitle = container.querySelector('.subtitle');

    expect(label?.textContent).toBe(mockProps.label);
    expect(subtitle?.textContent).toBe(mockProps.subtitle);
  });

  it('renders the tile subtile when a callback function is passed', async () => {
    const { container } = render(
      <MemoryRouter>
        <TileLarge {...mockProps} subtitle={() => Promise.resolve('135')} />
      </MemoryRouter>,
    );

    await waitFor(() => {
      const subtitle = container.querySelector('.subtitle');
      expect(subtitle?.textContent).toBe('135');
    });
  });

  it('does not show a subtitle in case of an error', async () => {
    const { container } = render(
      <MemoryRouter>
        <TileLarge {...mockProps} subtitle={() => Promise.reject('')} />
      </MemoryRouter>,
    );

    await waitFor(() => {
      const subtitle = container.querySelector('.subtitle');
      expect(subtitle?.textContent).toBe('');
    });
  });
  it.todo('does show a loading indicator while the subtitle is loading');

  it('renders an empty string if no subtitle is found', () => {
    const { container } = render(
      <MemoryRouter>
        <TileLarge {...mockProps} subtitle={undefined} />
      </MemoryRouter>,
    );

    const subtitle = container.querySelector('.subtitle');

    expect(subtitle?.textContent).toBe('');
  });

  it('renders an icon when passed as a string URL', () => {
    const { container } = render(
      <MemoryRouter>
        <TileLarge {...mockProps} />
      </MemoryRouter>,
    );
    const iconUrl = container.querySelector('img')?.getAttribute('src');

    expect(iconUrl).toBe(`${mockProps.icon}`);
  });

  it('renders an icon when passed as a react component', () => {
    const { container } = render(
      <MemoryRouter>
        <TileLarge {...mockProps} icon={<MockIcon />} />
      </MemoryRouter>,
    );
    const iconWrapper = container.querySelector('.icon');
    const svg = iconWrapper?.querySelector('svg');
    expect(svg).toBeInTheDocument();
  });

  it('to attrubute is not exists disabled class should be applied when disabled', () => {
    const { container } = render(
      <MemoryRouter>
        <TileLarge {...{ ...mockProps, disabled: true }} />
      </MemoryRouter>,
    );
    const tile = container.querySelector('.container');

    expect(tile?.classList.contains('disabled')).toBe(true);
  });

  it('creates a hyperlink using the path prop', () => {
    const { container } = render(
      <MemoryRouter>
        <TileLarge {...mockProps} />
      </MemoryRouter>,
    );

    const navLink = container.querySelector('.container') as HTMLAnchorElement;

    expect(navLink?.getAttribute('href')).toBe(mockProps.path);
  });

  it('sets row and column spans from props', () => {
    const mockColumnSpan = 3;
    const mockRowSpan = 1;
    const { container } = render(
      <MemoryRouter>
        <TileLarge
          {...mockProps}
          largeTileColumnSpan={mockColumnSpan}
          largeTileRowSpan={mockRowSpan}
        />
      </MemoryRouter>,
    );

    const navElement = container.querySelector('.container') as HTMLElement;

    expect(navElement.style.gridColumn).toBe(`span ${mockColumnSpan}`);
    expect(navElement.style.gridRow).toBe(`span ${mockRowSpan}`);
  });
});
