import { fireEvent, render } from '@testing-library/react';
import React from 'react';
import { describe, expect, it, vi } from 'vitest';
import { SortData } from '../../List.model';
import { ColumnLabel } from './ColumnLabel';

interface ColumnLabelTestData {
  id: number;
  title: string;
  desc: string;
}

describe('ColumnLabel', () => {
  it('renders the component without crashing', () => {
    const { container } = render(<ColumnLabel propertyName={'test-prop'} />);

    expect(container).toBeTruthy();
  });

  it('renders a label', () => {
    const mockLabel = 'test-label';
    const { container } = render(
      <ColumnLabel propertyName={'test-prop'} label={mockLabel} />,
    );

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

    expect(label?.textContent).toBe(mockLabel);
  });

  it('defaults to the property name if no label prop is passed in', () => {
    const mockPropName = 'test-prop';
    const { container } = render(<ColumnLabel propertyName={mockPropName} />);

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

    expect(label?.textContent).toBe(mockPropName);
  });

  it('renders the directional arrows by default', () => {
    const { container } = render(<ColumnLabel propertyName={'test-prop'} />);

    const dirArrows = container.querySelector('svg');
    const clickWrapper = container.querySelector('.clickWrapper');

    expect(dirArrows).toBeInTheDocument();
    expect(clickWrapper?.classList.contains('sortable')).toBe(true);
  });

  it('renders a label and no directional arrows if sorting is disabled', () => {
    const mockLabel = 'test-label';
    const { container } = render(
      <ColumnLabel
        propertyName={'test-prop'}
        label={mockLabel}
        sortable={false}
      />,
    );

    const label = container.querySelector('.label');
    const dirArrows = container.querySelector('svg');
    const containerDiv = container.querySelector('.container');

    expect(label?.textContent).toBe(mockLabel);
    expect(dirArrows).not.toBeInTheDocument();
    expect(containerDiv?.classList.contains('sortable')).toBe(false);
  });

  it(`sorts by 'ascending' order on initial sort`, () => {
    const spy = vi.fn();
    const mockColumnName = 'test-prop';
    const { container } = render(
      <ColumnLabel
        propertyName={mockColumnName}
        sortData={undefined}
        onSortChanged={spy}
      />,
    );

    const columnTitle = container.querySelector('.clickWrapper') as HTMLElement;
    fireEvent.click(columnTitle);

    expect(spy).toHaveBeenCalledTimes(1);
    expect(spy).toHaveBeenCalledWith({
      column: mockColumnName,
      direction: 'asc',
    });
  });

  it(`sorts by 'ascending' order when sorting by another column`, () => {
    const spy = vi.fn();
    const mockSortData: SortData<ColumnLabelTestData> = {
      column: 'title',
      direction: 'asc',
    };
    const mockColumnName = 'desc';
    const { container } = render(
      <ColumnLabel
        propertyName={mockColumnName}
        onSortChanged={spy}
        sortData={mockSortData}
      />,
    );

    const columnTitle = container.querySelector('.clickWrapper') as HTMLElement;
    fireEvent.click(columnTitle);

    expect(spy).toHaveBeenCalledTimes(1);
    expect(spy).toHaveBeenCalledWith({
      column: mockColumnName,
      direction: 'asc',
    });
  });

  it(`toggles sorting to 'descending' when sorting by 'ascending' in the same column`, () => {
    const spy = vi.fn();
    const mockSortData: SortData<ColumnLabelTestData> = {
      column: 'title',
      direction: 'asc',
    };
    const { container } = render(
      <ColumnLabel
        propertyName={mockSortData.column}
        onSortChanged={spy}
        sortData={mockSortData}
      />,
    );

    const columnTitle = container.querySelector('.clickWrapper') as HTMLElement;
    fireEvent.click(columnTitle);

    expect(spy).toHaveBeenCalledTimes(1);
    expect(spy).toHaveBeenCalledWith({
      column: mockSortData.column,
      direction: 'desc',
    });
  });

  it(`toggles sorting to 'ascending' when sorting by 'descending' in the same column`, () => {
    const spy = vi.fn();
    const mockSortData: SortData<ColumnLabelTestData> = {
      column: 'title',
      direction: 'desc',
    };
    const { container } = render(
      <ColumnLabel
        propertyName={mockSortData.column}
        onSortChanged={spy}
        sortData={mockSortData}
      />,
    );

    const columnTitle = container.querySelector('.clickWrapper') as HTMLElement;
    fireEvent.click(columnTitle);

    expect(spy).toHaveBeenCalledTimes(1);
    expect(spy).toHaveBeenCalledWith({
      column: mockSortData.column,
      direction: 'asc',
    });
  });

  it(`highlights up arrow when sort direction is 'ascending'`, () => {
    const mockSortData: SortData<ColumnLabelTestData> = {
      column: 'title',
      direction: 'asc',
    };
    const { container } = render(
      <ColumnLabel
        propertyName={mockSortData.column}
        sortData={mockSortData}
      />,
    );

    const paths = container.querySelectorAll('path');
    const upArrow = paths[0];

    expect(upArrow.classList.contains('sorted')).toBe(true);
  });

  it(`highlights up arrow when sort direction is 'descending'`, () => {
    const mockSortData: SortData<ColumnLabelTestData> = {
      column: 'title',
      direction: 'desc',
    };
    const { container } = render(
      <ColumnLabel
        propertyName={mockSortData.column}
        sortData={mockSortData}
      />,
    );

    const paths = container.querySelectorAll('path');
    const downArrow = paths[paths.length - 1];

    expect(downArrow.classList.contains('sorted')).toBe(true);
  });
});
