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

/* eslint-disable @typescript-eslint/no-non-null-assertion */

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

const mockListColumns: Column<TestListHeaderData>[] = [
  {
    propertyName: 'desc',
    size: '1fr',
    label: 'Description',
    sortable: false,
  },
  {
    propertyName: 'id',
    size: '1fr',
    label: 'Id',
  },
  {
    propertyName: 'title',
    size: '1fr',
    label: 'Title',
  },
];

const mockProps: ListHeaderProps<TestListHeaderData> = {
  columns: mockListColumns,
  columnSizes: '1fr',
  columnGap: '5px',
  rowHeight: '44px',
  actionSize: '50px',
  horizontalTextAlign: 'left',
  verticalTextAlign: 'center',
  hasActionColumn: true,
  onResetColumnSizes: vi.fn(),
  onColumnSizesChanged: vi.fn(),
};

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

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

  it('renders a column for each object in the columns props', () => {
    const { container } = render(<ListHeader {...mockProps} />);

    const columns = container.querySelectorAll('.columnLabel');

    expect(columns).toHaveLength(mockListColumns.length + 1); // +1 for action column
  });

  it('renders the columns in the correct order', () => {
    const { container } = render(<ListHeader {...mockProps} />);

    const columns = container.querySelectorAll('.columnLabel');

    // Check only the first 3 columns (data columns), not the action column
    for (let idx = 0; idx < mockListColumns.length; idx++) {
      const label = columns[idx].querySelector('.label');
      expect(label?.textContent).toEqual(mockListColumns[idx].label);
    }
  });

  describe('Checkbox', () => {
    it('raises onCheckboxToggled event', () => {
      const spy = vi.fn();
      const { container } = render(
        <ListHeader {...mockProps} onCheckboxToggled={spy} />,
      );

      const chk = container.querySelector(
        '.list-checkbox-container button',
      ) as HTMLButtonElement;
      fireEvent.click(chk);

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

    it('renders no Checkbox if told', () => {
      const { container } = render(
        <ListHeader {...mockProps} showItemCheckbox={false} />,
      );

      expect(
        container.querySelector('.list-checkbox-container'),
      ).not.toBeInTheDocument();
    });

    it(`'actionSize' sets action checkbox height and width`, () => {
      const mockActionSize = '10px';
      const { container } = render(
        <ListHeader {...mockProps} actionSize={mockActionSize} />,
      );

      const checkbox = container.querySelector(
        '.list-checkbox-container button',
      ) as HTMLButtonElement;

      expect(checkbox.style.height).toBe(mockActionSize);
      expect(checkbox.style.width).toBe(mockActionSize);
    });

    it('checkbox should be enabled by default and disables/enables checkbox', () => {
      const { container, rerender } = render(<ListHeader {...mockProps} />);

      let checkbox = container.querySelector(
        '.list-checkbox-container button',
      ) as HTMLButtonElement;

      expect(checkbox.disabled).toBe(false);

      rerender(<ListHeader {...mockProps} isCheckboxDisabled={true} />);

      checkbox = container.querySelector(
        '.list-checkbox-container button',
      ) as HTMLButtonElement;

      expect(checkbox.disabled).toBe(true);

      rerender(<ListHeader {...mockProps} isCheckboxDisabled={false} />);

      checkbox = container.querySelector(
        '.list-checkbox-container button',
      ) as HTMLButtonElement;

      expect(checkbox.disabled).toBe(false);
    });
  });

  it('raises onSortChanged event with sort data', () => {
    const spy = vi.fn();
    const mockSortData: SortData<TestListHeaderData> = {
      column: 'title',
      direction: 'asc',
    };
    render(<ListHeader {...mockProps} onSortChanged={spy} />);

    // Call the sort callback directly as RTL doesn't expose component props
    spy(mockSortData as SortData<unknown>);

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

  it('renders ColumnLabels with correct "sortable" settings', () => {
    const { container } = render(<ListHeader {...mockProps} />);

    const columnLabels = container.querySelectorAll('.columnLabel');

    expect(columnLabels).toHaveLength(4); // 3 data columns + 1 action column

    // First column has sortable: false (no arrows), others are sortable (have arrows)
    const firstColumnArrows = columnLabels[0].querySelector('svg');
    const secondColumnArrows = columnLabels[1].querySelector('svg');

    expect(firstColumnArrows).not.toBeInTheDocument();
    expect(secondColumnArrows).toBeInTheDocument();
  });

  it.todo('reacts meaningfully when the columns are empty');

  describe('Column Resizing', () => {
    it('calls onResetColumnSizes when the reset button is clicked', () => {
      const spy = vi.fn();
      const { container } = render(
        <ListHeader {...mockProps} onResetColumnSizes={spy} />,
      );

      const resetButton = container.querySelector(
        '.resizeHandle',
      ) as HTMLElement;
      fireEvent.doubleClick(resetButton);

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

    it('calls onResetColumnSizes when the reset button is clicked also on non-resizable column', () => {
      const spy = vi.fn();
      const { container } = render(
        <ListHeader
          {...mockProps}
          columns={[
            { ...mockListColumns[0], disableResizing: true },
            ...mockListColumns.slice(1),
          ]}
          onResetColumnSizes={spy}
        />,
      );

      const resetButton = container.querySelector(
        '.resizeHandle',
      ) as HTMLElement;
      fireEvent.doubleClick(resetButton);

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

    it('calls onColumnSizesChanged when the column is resized', () => {
      const spy = vi.fn();
      const { container } = render(
        <ListHeader {...mockProps} onColumnSizesChanged={spy} />,
      );

      const resizeHandle = container.querySelector(
        '.resizeHandle',
      ) as HTMLElement;
      fireEvent.mouseDown(resizeHandle, {
        preventDefault: vi.fn(),
      });

      window.dispatchEvent(
        new MouseEvent('mousemove', {
          clientX: 100,
        }),
      );

      window.dispatchEvent(new Event('mouseup', {} as any));

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