import React from 'react';
import { render, fireEvent } from '@testing-library/react';
import { formatMessage } from '@theorchard/suite-i18n';
import { TestData } from 'lib/test-utils/table';
import * as LayoutApi from '../../../base/api/layout';
import { GridTable } from '../../../base/table';
import { TableExtensions } from '../../../base/tableExtensions';
import { TableProps } from '../../../base/types';
import { TableActionsExtension } from '../tableActionsExtension';

TableExtensions.addExtension(TableActionsExtension);

describe('TableActionsExtension', () => {
    const data: TestData[] = [
        { name: 'row-1', value: 2 },
        { name: 'row-2', value: 1 },
    ];

    const defaultProps: TableProps<TestData> = {
        rowActions: {
            edit: vi.fn(),
            delete: vi.fn(),
        },
        rowKey: 'name',
        data,
    };

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

    describe('with "rowActions"', () => {
        describe('table does not overflow', () => {
            beforeEach(() => {
                vi.spyOn(LayoutApi, 'useLayoutInfo').mockReturnValue({
                    refresh: vi.fn(),
                    layoutInfo: {
                        overflowing: false,
                        overflowed: false,
                        overflowX: 0,
                    },
                });
            });

            test('renders actions buttons', () => {
                const { getAllByTestId } = renderTable();

                const editButtons = getAllByTestId('TableActionButton-edit');
                const deleteButtons = getAllByTestId('TableActionButton-delete');

                expect(editButtons).toHaveLength(data.length);
                expect(deleteButtons).toHaveLength(data.length);
            });
        });

        describe('table overflows under threshold', () => {
            beforeEach(() => {
                vi.spyOn(LayoutApi, 'useLayoutInfo').mockReturnValue({
                    refresh: vi.fn(),
                    layoutInfo: {
                        overflowing: true,
                        overflowed: true,
                        overflowX: 24 + 15,
                    },
                });
            });

            test('renders overlay actions buttons', () => {
                const { getAllByTestId } = renderTable();

                const editButtons = getAllByTestId('TableActionButton-edit');
                const deleteButtons = getAllByTestId('TableActionButton-delete');

                expect(editButtons).toHaveLength(data.length);
                expect(deleteButtons).toHaveLength(data.length);
            });
        });

        describe('table overflows above threshold', () => {
            beforeEach(() => {
                vi.spyOn(LayoutApi, 'useLayoutInfo').mockReturnValue({
                    refresh: vi.fn(),
                    layoutInfo: {
                        overflowing: true,
                        overflowed: true,
                        overflowX: 24 + 15 + 1,
                    },
                });
            });

            test('renders overlay actions buttons', () => {
                const { getAllByTestId } = renderTable();

                const editButtons = getAllByTestId('TableActionButton-edit');
                const deleteButtons = getAllByTestId('TableActionButton-delete');

                expect(editButtons).toHaveLength(data.length * 2);
                expect(deleteButtons).toHaveLength(data.length * 2);
            });
        });
    });

    describe('tooltip', () => {
        test('adds tooltip', async () => {
            const { getAllByText, findByText } = renderTable({
                rowActions: {
                    test: {
                        icon: <>BUTTON</>,
                        tooltip: 'test',
                        onClick: vi.fn(),
                    },
                },
            });

            const button = getAllByText('BUTTON')[0];
            fireEvent.mouseOver(button);
            const tooltip = await findByText('test');
            expect(tooltip).toBeVisible();
            expect(tooltip).toHaveClass('tooltip-inner');
        });

        test('adds tooltip based on function', async () => {
            const { getAllByText, findByText } = renderTable({
                rowActions: {
                    test: {
                        icon: <>BUTTON</>,
                        tooltip: (row) => `tooltip for ${row.name}`,
                        onClick: vi.fn(),
                    },
                },
            });

            const button = getAllByText('BUTTON')[2];
            fireEvent.mouseOver(button);
            const tooltip = await findByText('tooltip for row-2');
            expect(tooltip).toBeInTheDocument();
            expect(tooltip).toHaveClass('tooltip-inner');
        });
    });

    describe('rowActionsHeader', () => {
        test('defaults to `Actions`', () => {
            const { getByText } = renderTable();
            const header = getByText(formatMessage('table_actions'));
            expect(header).toBeInTheDocument();
            expect(header).toHaveClass('GridTable-column-text');
        });

        test('can be overriden with custom header name', () => {
            const rowActionsHeader = 'TEST NAME';
            const { getByText, queryByText } = renderTable({ rowActionsHeader });
            expect(queryByText(formatMessage('table_actions'))).toBeNull();

            const header = getByText(formatMessage(rowActionsHeader));
            expect(header).toBeInTheDocument();
            expect(header).toHaveClass('GridTable-column-text');
        });
    });
});
