import React from 'react';
import { screen, render, fireEvent } from '@testing-library/react';
import { GridTable } from '../../../base/table';
import { TableExtensions } from '../../../base/tableExtensions';
import { TableProps } from '../../../base/types';
import { TableGroupedRowsExtension } from '../tableGroupedRowsExtension';

TableExtensions.addExtension(TableGroupedRowsExtension);

interface Data {
    id: string;
    name: string;
    value: string;
    num: number;
}

describe('tableGroupedRowsExtension', () => {
    const test1ValueA = 'test1valueA';
    const test1ValueB = 'test1valueB';
    const test2Value = 'test2value';
    const data: Data[] = [
        { id: 'a', name: 'test1', value: test1ValueA, num: 3 },
        { id: 'b', name: 'test1', value: test1ValueB, num: 1 },
        { id: 'c', name: 'test2', value: test2Value, num: 2 },
    ];

    const defaultProps: TableProps<Data> = {
        columnDefs: [{ name: 'name' }, { name: 'value' }, { name: 'num', sortable: true }],
        data,
    };

    const renderTable = (props: Partial<TableProps<Data>> = {}) =>
        render(<GridTable {...defaultProps} {...props} />);

    describe('with one grouped row', () => {
        test('renders two visible rows', () => {
            renderTable({
                grouped: {
                    aggregationKey: (data) => data.name,
                    expandedGroups: {},
                },
            });

            const test1 = screen.getAllByText('test1');
            expect(test1.length).toBe(1);
            expect(test1[0]).toBeVisible();

            const test2 = screen.getAllByText('test1');
            expect(test2.length).toBe(1);
            expect(test2[0]).toBeVisible();
        });

        test('renders three visible rows when group is expanded', () => {
            renderTable({
                grouped: {
                    aggregationKey: (data) => data.name,
                    expandedGroups: { test1: true },
                },
            });

            const test1 = screen.getAllByText('test1');
            expect(test1.length).toBe(2);
            test1.forEach((el) => expect(el).toBeVisible());

            const test2 = screen.getAllByText('test2');
            expect(test2.length).toBe(1);
            expect(test2[0]).toBeVisible();
        });

        test('renders spanned column correctly', () => {
            renderTable({
                grouped: {
                    aggregationKey: (data) => data.name,
                    expandedGroups: { test1: true },
                    rowSpanColumns: ['name'],
                },
            });

            expect(screen.getByText(test1ValueA)).toBeVisible();
            expect(screen.getByText(test1ValueB)).toBeVisible();

            const test1 = screen.getAllByText('test1');
            expect(test1.length).toBe(1);
            expect(test1[0]).toBeVisible();

            const test2 = screen.getAllByText('test2');
            expect(test2.length).toBe(1);
            expect(test2[0]).toBeVisible();
        });

        test('grouped rows are wrapped in container', () => {
            const { container } = renderTable({
                grouped: {
                    aggregationKey: (data) => data.name,
                    expandedGroups: { test1: true },
                },
            });

            const wrapper = container.getElementsByClassName('TableGroupedRows-group')?.[0];
            expect(wrapper).toHaveTextContent(test1ValueA);
            expect(wrapper).toHaveTextContent(test1ValueB);
        });

        test('groups rows when sorted', () => {
            const { container } = renderTable({
                grouped: {
                    aggregationKey: (data) => data.name,
                    expandedGroups: { test1: true },
                },
            });

            const preSort = container.querySelectorAll('.GridTable-cell.cell-num');
            expect(preSort[0].textContent).toBe('3');
            expect(preSort[1].textContent).toBe('1');
            expect(preSort[2].textContent).toBe('2');

            const sortHeader = container.getElementsByClassName('sortable');
            if (sortHeader[0]) fireEvent.click(sortHeader[0]);

            const postSort = container.querySelectorAll('.GridTable-cell.cell-num');
            expect(postSort[0].textContent).toBe('1');
            expect(postSort[1].textContent).toBe('3');
            expect(postSort[2].textContent).toBe('2');
        });
    });

    describe('with no grouped row', () => {
        test('renders three visible rows', () => {
            renderTable({
                grouped: {
                    aggregationKey: (data) => data.id,
                    expandedGroups: {},
                },
            });

            const test1 = screen.getAllByText('test1');
            expect(test1.length).toBe(2);
            test1.forEach((el) => expect(el).toBeVisible());

            const test2 = screen.getAllByText('test2');
            expect(test2.length).toBe(1);
            expect(test2[0]).toBeVisible();
        });
    });
});
