import { render, screen } from '@testing-library/vue';
import userEvent from '@testing-library/user-event';
import type { Table } from '@aleph-alpha/ui-library';
import { describe, expect, test, vi } from 'vitest';
import UiDataTableColumnFilter from '../UiDataTableColumnFilter.vue';

interface TestData {
  id: string;
  status: string;
  amount: number;
}

type MockColumn = {
  id: string;
  columnDef: {
    header?: unknown;
    meta?: { label?: string };
  };
  getCanHide: ReturnType<typeof vi.fn>;
  getIsVisible: ReturnType<typeof vi.fn>;
  toggleVisibility: ReturnType<typeof vi.fn>;
};

function createMockColumn(options: {
  id: string;
  header?: unknown;
  metaLabel?: string;
  canHide?: boolean;
  isVisible?: boolean;
}): MockColumn {
  const { id, header, metaLabel, canHide = true, isVisible = true } = options;

  return {
    id,
    columnDef: {
      header,
      meta: metaLabel ? { label: metaLabel } : undefined,
    },
    getCanHide: vi.fn(() => canHide),
    getIsVisible: vi.fn(() => isVisible),
    toggleVisibility: vi.fn(),
  };
}

function createMockTable(columns: MockColumn[]) {
  return {
    getAllLeafColumns: vi.fn(() => columns),
  } as unknown as Table<TestData>;
}

describe('UiDataTableColumnFilter', () => {
  test('uses custom labels for the trigger', async () => {
    const user = userEvent.setup();
    const table = createMockTable([
      createMockColumn({ id: 'status', header: 'Status' }),
    ]);

    render(UiDataTableColumnFilter, {
      props: {
        table: table as never,
        labels: {
          columns: 'Spalten',
          toggleColumns: 'Spalten umschalten',
          columnVisibility: 'Spaltensichtbarkeit',
        },
      },
    });

    const trigger = screen.getByRole('button', { name: 'Spalten umschalten' });
    expect(trigger.textContent).toContain('Spalten');

    await user.click(trigger);

    expect(screen.queryByText('Spaltensichtbarkeit')).toBeNull();
    expect(
      screen.getByRole('menuitemcheckbox', { name: 'Status' }),
    ).toBeTruthy();
  });

  test('uses toggle styling for trigger and body text for items', async () => {
    const user = userEvent.setup();
    const table = createMockTable([
      createMockColumn({ id: 'status', header: 'Status' }),
    ]);

    render(UiDataTableColumnFilter, { props: { table: table as never } });

    const trigger = screen.getByRole('button', { name: 'Toggle columns' });
    expect(trigger.className).toContain('label-14-medium');
    expect(trigger.className).toContain('font-medium');
    expect(trigger.querySelectorAll('[data-slot="icon"]')).toHaveLength(2);

    await user.click(trigger);
    expect(trigger.getAttribute('data-state')).toBe('open');
    expect(trigger.getAttribute('aria-pressed')).toBe('true');
    expect(
      trigger.querySelectorAll('[data-slot="icon"]')[1]?.getAttribute('class'),
    ).toContain('rotate-180');

    const itemClassName = screen.getByRole('menuitemcheckbox', {
      name: 'Status',
    }).className;
    expect(itemClassName).toContain('body-14-regular');
    expect(itemClassName).toContain('gap-2');
    expect(itemClassName).toContain('p-2');
    expect(itemClassName).toContain('pl-8');
    expect(itemClassName).toContain('font-normal');

    await user.keyboard('{Escape}');

    expect(trigger.getAttribute('data-state')).toBe('closed');
    expect(trigger.getAttribute('aria-pressed')).toBe('false');
  });

  test('prefers meta label over string header and falls back to column id', async () => {
    const user = userEvent.setup();
    const table = createMockTable([
      createMockColumn({
        id: 'status',
        header: 'Status header',
        metaLabel: 'Workflow status',
      }),
      createMockColumn({ id: 'amount', header: 'Amount' }),
      createMockColumn({ id: 'createdAt', header: () => 'Created at' }),
    ]);

    render(UiDataTableColumnFilter, { props: { table } });

    await user.click(screen.getByRole('button', { name: 'Toggle columns' }));

    expect(
      screen.getByRole('menuitemcheckbox', { name: 'Workflow status' }),
    ).toBeInTheDocument();
    expect(
      screen.queryByRole('menuitemcheckbox', { name: 'Status header' }),
    ).not.toBeInTheDocument();
    expect(
      screen.getByRole('menuitemcheckbox', { name: 'Amount' }),
    ).toBeInTheDocument();
    expect(
      screen.getByRole('menuitemcheckbox', { name: 'createdAt' }),
    ).toBeInTheDocument();
  });

  test('omits columns with enableHiding false', async () => {
    const user = userEvent.setup();
    const table = createMockTable([
      createMockColumn({ id: 'status', header: 'Status' }),
      createMockColumn({
        id: 'select',
        header: 'Select',
        canHide: false,
      }),
    ]);

    render(UiDataTableColumnFilter, { props: { table } });

    await user.click(screen.getByRole('button', { name: 'Toggle columns' }));

    expect(
      screen.getByRole('menuitemcheckbox', { name: 'Status' }),
    ).toBeInTheDocument();
    expect(
      screen.queryByRole('menuitemcheckbox', { name: 'Select' }),
    ).not.toBeInTheDocument();
  });

  test('toggles column visibility from checkbox menu items', async () => {
    const user = userEvent.setup();
    const visibleColumn = createMockColumn({
      id: 'status',
      header: 'Status',
      isVisible: true,
    });
    const hiddenColumn = createMockColumn({
      id: 'amount',
      header: 'Amount',
      isVisible: false,
    });
    const table = createMockTable([visibleColumn, hiddenColumn]);

    render(UiDataTableColumnFilter, { props: { table } });

    const trigger = screen.getByRole('button', { name: 'Toggle columns' });

    await user.click(trigger);
    await user.click(screen.getByRole('menuitemcheckbox', { name: 'Status' }));
    await user.click(trigger);
    await user.click(screen.getByRole('menuitemcheckbox', { name: 'Amount' }));

    expect(visibleColumn.toggleVisibility).toHaveBeenCalledWith(false);
    expect(hiddenColumn.toggleVisibility).toHaveBeenCalledWith(true);
  });
});
