import { render } from '@testing-library/vue';
import userEvent from '@testing-library/user-event';
import { describe, expect, test, vi } from 'vitest';
import UiDataTableColumnHeader from '../UiDataTableColumnHeader.vue';

// Mock column object that mimics TanStack Table's Column interface
/**
 *
 * @param options
 * @param options.canSort
 * @param options.isSorted
 */
function createMockColumn(
  options: { canSort?: boolean; isSorted?: false | 'asc' | 'desc' } = {},
) {
  const { canSort = true, isSorted = false } = options;
  return {
    getCanSort: vi.fn(() => canSort),
    getIsSorted: vi.fn(() => isSorted),
    toggleSorting: vi.fn(),
    clearSorting: vi.fn(),
  };
}

describe('UiDataTableColumnHeader', () => {
  describe('Rendering', () => {
    test('renders title text', () => {
      const column = createMockColumn();
      const { getByText } = render(UiDataTableColumnHeader, {
        props: { column, title: 'Status' },
      });

      expect(getByText('Status')).toBeInTheDocument();
    });

    test('renders as plain text when column is not sortable', () => {
      const column = createMockColumn({ canSort: false });
      const { getByText, queryByRole } = render(UiDataTableColumnHeader, {
        props: { column, title: 'Actions' },
      });

      expect(getByText('Actions')).toBeInTheDocument();
      expect(queryByRole('button')).not.toBeInTheDocument();
    });

    test('renders as button when column is sortable', () => {
      const column = createMockColumn({ canSort: true });
      const { getByRole } = render(UiDataTableColumnHeader, {
        props: { column, title: 'Name' },
      });

      expect(getByRole('button', { name: /Name/i })).toBeInTheDocument();
    });

    test('keeps sortable title outside the sort button', () => {
      const column = createMockColumn({ canSort: true });
      const { getByRole } = render(UiDataTableColumnHeader, {
        props: { column, title: 'Name' },
      });

      expect(getByRole('button', { name: /Name/i })).not.toHaveTextContent(
        'Name',
      );
    });

    test('applies custom class to container', () => {
      const column = createMockColumn();
      const { container } = render(UiDataTableColumnHeader, {
        props: { column, title: 'Amount' },
        attrs: { class: 'justify-end' },
      });

      expect(container.firstElementChild).toHaveClass('justify-end');
    });
  });

  describe('Click-to-Sort', () => {
    test('sorts ascending when unsorted column is clicked', async () => {
      const user = userEvent.setup();
      const column = createMockColumn({ isSorted: false });
      const { getByRole } = render(UiDataTableColumnHeader, {
        props: { column, title: 'Name' },
      });

      await user.click(getByRole('button'));

      expect(column.toggleSorting).toHaveBeenCalledWith(false);
    });

    test('sorts descending when ascending column is clicked', async () => {
      const user = userEvent.setup();
      const column = createMockColumn({ isSorted: 'asc' });
      const { getByRole } = render(UiDataTableColumnHeader, {
        props: { column, title: 'Name' },
      });

      await user.click(getByRole('button'));

      expect(column.toggleSorting).toHaveBeenCalledWith(true);
    });

    test('clears sorting when descending column is clicked', async () => {
      const user = userEvent.setup();
      const column = createMockColumn({ isSorted: 'desc' });
      const { getByRole } = render(UiDataTableColumnHeader, {
        props: { column, title: 'Name' },
      });

      await user.click(getByRole('button'));

      expect(column.clearSorting).toHaveBeenCalled();
    });
  });

  describe('Accessibility', () => {
    test('displays correct aria-label based on sort state', () => {
      // Test unsorted
      const unsortedColumn = createMockColumn({ isSorted: false });
      const { getByRole: getUnsorted, unmount: unmountUnsorted } = render(
        UiDataTableColumnHeader,
        {
          props: { column: unsortedColumn, title: 'Name' },
        },
      );
      expect(getUnsorted('button')).toHaveAttribute(
        'aria-label',
        'Name, click to sort',
      );
      unmountUnsorted();

      // Test ascending
      const ascColumn = createMockColumn({ isSorted: 'asc' });
      const { getByRole: getAsc, unmount: unmountAsc } = render(
        UiDataTableColumnHeader,
        {
          props: { column: ascColumn, title: 'Name' },
        },
      );
      expect(getAsc('button')).toHaveAttribute(
        'aria-label',
        'Name, sorted ascending',
      );
      unmountAsc();

      // Test descending
      const descColumn = createMockColumn({ isSorted: 'desc' });
      const { getByRole: getDesc } = render(UiDataTableColumnHeader, {
        props: { column: descColumn, title: 'Name' },
      });
      expect(getDesc('button')).toHaveAttribute(
        'aria-label',
        'Name, sorted descending',
      );
    });
  });

  describe('i18n Support', () => {
    test('uses custom aria labels when provided', () => {
      const column = createMockColumn({ isSorted: 'asc' });
      const { getByRole } = render(UiDataTableColumnHeader, {
        props: {
          column,
          title: 'Name',
          labels: { sortedAscending: 'aufsteigend sortiert' },
        },
      });

      expect(getByRole('button')).toHaveAttribute(
        'aria-label',
        'Name, aufsteigend sortiert',
      );
    });

    test('uses custom clickToSort label in aria-label', () => {
      const column = createMockColumn({ isSorted: false });
      const { getByRole } = render(UiDataTableColumnHeader, {
        props: {
          column,
          title: 'Email',
          labels: { clickToSort: 'zum Sortieren klicken' },
        },
      });

      expect(getByRole('button')).toHaveAttribute(
        'aria-label',
        'Email, zum Sortieren klicken',
      );
    });

    test('uses custom sortedDescending label in aria-label', () => {
      const column = createMockColumn({ isSorted: 'desc' });
      const { getByRole } = render(UiDataTableColumnHeader, {
        props: {
          column,
          title: 'Amount',
          labels: { sortedDescending: 'absteigend sortiert' },
        },
      });

      expect(getByRole('button')).toHaveAttribute(
        'aria-label',
        'Amount, absteigend sortiert',
      );
    });
  });
});
