import React, { FC } from 'react';
import { render } from '@testing-library/react';
import { TableColumnTemplates } from '../../tableColumnTemplates';
import { ColumnDefinition, GridTableCustomColumn, SortByConfig } from '../../types';
import { createColumnDefinitions, createColumnInstances } from '../columns';

describe('createColumnDefinitions', () => {
    describe('from children', () => {
        const col1 = { name: 'col1', className: 'col1-class' };
        const col2 = { name: 'col2', extraProp: 'something' };

        test('creates column definitions from react children', () => {
            const result = createColumnDefinitions({
                children: [React.createElement('div', col1), React.createElement('div', col2)],
            });

            expect(result).toEqual([col1, col2]);
        });

        test('excludes hidden columns', () => {
            const col3: ColumnDefinition = {
                name: 'col3',
                visibility: 'hidden',
            };

            const result = createColumnDefinitions({
                children: [
                    React.createElement('div', col1),
                    React.createElement('div', col3),
                    React.createElement('div', col2),
                ],
            });

            expect(result).toEqual([col1, col2]);
        });

        test('includes collapsed columns', () => {
            const col3: ColumnDefinition = {
                name: 'col3',
                visibility: 'collapse',
            };

            const result = createColumnDefinitions({
                children: [
                    React.createElement('div', col1),
                    React.createElement('div', col2),
                    React.createElement('div', col3),
                ],
            });

            expect(result).toEqual([col1, col2, col3]);
        });

        test('merges with defined templates', () => {
            const col3: ColumnDefinition = {
                name: 'col3',
                template: 'number',
            };

            const result = createColumnDefinitions({
                children: React.createElement('div', col3),
            });

            expect(result).toEqual([
                {
                    ...col3,
                    ...TableColumnTemplates.number,
                },
            ]);
        });

        describe('with "renderCell" function', () => {
            test('is registered with custom render function', () => {
                const testMessage = 'hi there';

                const LegacyColumn: GridTableCustomColumn<{
                    message: string;
                }> = () => <></>;

                LegacyColumn.renderCell = (Cell) => <Cell message={testMessage} />;

                const result = createColumnDefinitions({
                    children: (
                        <LegacyColumn name="test" Cell={({ message }) => <>CELL:{message}</>} />
                    ),
                });

                const Cell = result[0].Cell! as FC;

                const { getByText } = render(<Cell />);

                expect(getByText(`CELL:${testMessage}`)).toBeInTheDocument();

                expect(result).toEqual([
                    {
                        Cell: expect.any(Function),
                        name: 'test',
                    },
                ]);
            });
        });

        describe('with "renderHeaderText" function', () => {
            test('is registered with custom HeaderText component', () => {
                const testTerm = 'testHeader';

                const LegacyColumn: GridTableCustomColumn<object, { term: string }> = () => <></>;

                LegacyColumn.renderHeaderText = (props) => (
                    <div>Translated:{props.columnDef.term}</div>
                );

                const result = createColumnDefinitions({
                    children: <LegacyColumn name="test" term={testTerm} />,
                });

                const HeaderText = result[0].HeaderText!;

                const { getByText } = render(
                    <HeaderText title="not rendered" columnDef={result[0]} rows={[]} />
                );

                expect(getByText(`Translated:${testTerm}`)).toBeInTheDocument();

                expect(result).toEqual([
                    {
                        HeaderText: expect.any(Function),
                        name: 'test',
                        term: testTerm,
                    },
                ]);
            });
        });
    });

    describe('from data', () => {
        test('creates column definitions from first row properties', () => {
            const result = createColumnDefinitions({
                data: [
                    {
                        name: 'test',
                        value: 'value',
                        other: 'prop',
                    },
                ],
            });

            expect(result).toEqual([{ name: 'name' }, { name: 'value' }, { name: 'other' }]);
        });

        test('returns empty if no rows', () => {
            const result = createColumnDefinitions({ data: [] });

            expect(result).toEqual([]);
        });
    });
});

describe('createColumnInstances', () => {
    const getSortConfig = () => undefined;

    describe('with column empty title', () => {
        test('returns column with "hasSeparator" false', () => {
            const [column] = createColumnInstances({
                getSortConfig,
                columnDefs: [
                    {
                        name: 'name',
                        title: '',
                    },
                ],
            });

            expect(column.hasSeparator).toEqual(false);
        });
    });

    describe('with column separator = false', () => {
        test('returns column with "hasSeparator" false', () => {
            const [column] = createColumnInstances({
                getSortConfig,
                columnDefs: [
                    {
                        name: 'name',
                        title: 'Name',
                        separator: false,
                    },
                ],
            });

            expect(column.hasSeparator).toEqual(false);
        });
    });

    test('assigns column sort configuration', () => {
        const col1 = 'col1';
        const sortConfig: SortByConfig = {
            key: col1,
            index: 0,
            direction: 'asc',
        };

        const [instance1, instance2] = createColumnInstances({
            getSortConfig: (name: string) => (name === col1 ? sortConfig : undefined),
            columnDefs: [
                {
                    name: col1,
                    title: 'Column One',
                    separator: false,
                },
                {
                    name: 'col2',
                    title: 'Column Two',
                    separator: false,
                },
            ],
        });

        expect(instance1.sortConfig).toBe(sortConfig);
        expect(instance2.sortConfig).toBeUndefined();
    });
});
