import React from 'react';
import { screen, fireEvent, waitFor } from '@testing-library/react';
import { renderInAppContext } from '@theorchard/suite-testing';
import { MAIN_CONTENT_CLASSNAME, OA_VENDOR_URL } from 'src/constants';
import { CLASS_NAME } from '../bulkSessionIngestionList';
import BulkSessionIngestionList from '..';

jest.mock('src/pages/adminPage/components/ingestionDetails', () => ({
    __esModule: true,
    default: ({
        bulkSessionIngestionId,
    }: {
        bulkSessionIngestionId: string;
    }) => <div>Mock IngestionDetails {bulkSessionIngestionId}</div>,
}));

jest.mock('@theorchard/suite-components', () => {
    // eslint-disable-next-line @typescript-eslint/no-require-imports
    const ReactLib = require('react');

    const MockGridTable = ({
        data = [],
        children,
        rowActions,
        onRowClick,
        expandedRows = {},
        rowKey = (row: any) => row.id,
    }: any) => {
        const columns = ReactLib.Children.toArray(children);

        return (
            <div data-testid="GridTable">
                <div>
                    {columns.map((column: any, index: number) => (
                        <span key={`${column.props.name}-${index}`}>
                            {column.props.title}
                        </span>
                    ))}
                </div>
                {data.map((row: any) => (
                    <div key={row.id}>
                        <button
                            type="button"
                            aria-label={`Expand ${row.id}`}
                            onClick={() => onRowClick?.({ key: rowKey(row) })}
                        >
                            Expand
                        </button>
                        {columns.map((column: any, index: number) => {
                            const Cell = column.props.Cell;

                            return (
                                <div
                                    key={`${row.id}-${column.props.name}-${index}`}
                                >
                                    {Cell
                                        ? Cell({ data: row })
                                        : row[column.props.name]}
                                </div>
                            );
                        })}
                        {Object.values(rowActions ?? {}).map(
                            (action: any, index: number) => (
                                <button
                                    key={`${row.id}-action-${index}`}
                                    onClick={() => action.onClick(row)}
                                    aria-label={action.tooltip}
                                    type="button"
                                >
                                    {action.tooltip}
                                </button>
                            )
                        )}
                        {expandedRows[rowKey(row)] ? (
                            <div data-testid={`expanded-${row.id}`}>
                                {ReactLib.createElement(
                                    expandedRows[rowKey(row)]
                                )}
                            </div>
                        ) : null}
                    </div>
                ))}
            </div>
        );
    };

    MockGridTable.Column = () => null;

    return {
        GridTable: MockGridTable,
        Status: ({ text }: { text: string }) => <span>{text}</span>,
    };
});

const items = [
    {
        id: 'ing-1',
        ingestionStatus: 'success',
        completedOn: null,
        bulkSession: {
            id: 'sess-1',
            slug: 'sess-slug-1',
            downloadLink: null,
            totalProducts: null,
            createdBy: null,
            label: {
                __typename: 'Subaccount' as const,
            },
        },
    },
    {
        id: 'ing-2',
        ingestionStatus: 'failure',
        completedOn: null,
        bulkSession: {
            id: 'sess-2',
            slug: 'sess-slug-2',
            downloadLink: null,
            totalProducts: null,
            createdBy: null,
            label: {
                __typename: 'Subaccount' as const,
            },
        },
    },
];

describe('BulkSessionIngestionList', () => {
    test('renders the container with the correct class name', () => {
        const { container } = renderInAppContext(
            <BulkSessionIngestionList
                items={[]}
                totalCount={0}
                loading={false}
            />
        );

        expect(container.querySelector(`.${CLASS_NAME}`)).toBeInTheDocument();
    });

    test('renders column headers', () => {
        renderInAppContext(
            <BulkSessionIngestionList
                items={items}
                totalCount={items.length}
                loading={false}
            />
        );

        expect(screen.getByText('Status')).toBeInTheDocument();
        expect(screen.getByText('Bulk Session')).toBeInTheDocument();
        expect(screen.getByText('Label')).toBeInTheDocument();
        expect(screen.queryByText('Created By')).not.toBeInTheDocument();
    });

    test('invokes metadata download row action', () => {
        const clickSpy = jest.fn();
        const realCreateElement = document.createElement.bind(document);
        const createElementSpy = jest
            .spyOn(document, 'createElement')
            .mockImplementation(((tagName: string) => {
                const element = realCreateElement(tagName);

                if (tagName.toLowerCase() === 'a') {
                    Object.defineProperty(element, 'click', {
                        value: clickSpy,
                        configurable: true,
                    });
                }

                return element;
            }) as typeof document.createElement);

        const downloadItems = [
            {
                ...items[0],
                bulkSession: {
                    ...items[0].bulkSession,
                    downloadLink: 'https://example.com/metadata.xlsx',
                },
            },
        ];

        renderInAppContext(
            <BulkSessionIngestionList
                items={downloadItems as never[]}
                totalCount={downloadItems.length}
                loading={false}
            />
        );

        fireEvent.click(
            screen.getByRole('button', { name: 'Download Metadata' })
        );

        expect(createElementSpy).toHaveBeenCalledWith('a');
        expect(clickSpy).toHaveBeenCalled();

        createElementSpy.mockRestore();
    });

    test('renders a row for each item', () => {
        renderInAppContext(
            <BulkSessionIngestionList
                items={items}
                totalCount={items.length}
                loading={false}
            />
        );

        expect(screen.getByText('sess-slug-1')).toBeInTheDocument();
        expect(screen.getByText('sess-slug-2')).toBeInTheDocument();
    });

    test('expands and collapses ingestion details on row click', () => {
        renderInAppContext(
            <BulkSessionIngestionList
                items={items}
                totalCount={items.length}
                loading={false}
            />
        );

        fireEvent.click(screen.getByRole('button', { name: 'Expand ing-1' }));
        expect(
            screen.getByText('Mock IngestionDetails ing-1')
        ).toBeInTheDocument();

        fireEvent.click(screen.getByRole('button', { name: 'Expand ing-1' }));
        expect(
            screen.queryByText('Mock IngestionDetails ing-1')
        ).not.toBeInTheDocument();
    });

    test('renders in loading state without throwing', () => {
        const { container } = renderInAppContext(
            <BulkSessionIngestionList
                items={[]}
                totalCount={0}
                loading={true}
            />
        );

        expect(
            container.querySelector('[data-testid="GridTable"]')
        ).toBeInTheDocument();
    });

    test('renders without InfiniteScroll when fetchMore is not provided', () => {
        const { container } = renderInAppContext(
            <BulkSessionIngestionList
                items={items}
                totalCount={items.length}
                loading={false}
            />
        );

        expect(
            container.querySelector('[data-testid="InfiniteScroll"]')
        ).not.toBeInTheDocument();
        expect(screen.getByText('sess-slug-1')).toBeInTheDocument();
    });

    test('wraps GridTable with InfiniteScroll when fetchMore is provided', () => {
        const { container } = renderInAppContext(
            <BulkSessionIngestionList
                items={items}
                totalCount={items.length}
                loading={false}
                fetchMore={jest.fn()}
            />
        );

        expect(
            container.querySelector('[data-testid="InfiniteScroll"]')
        ).toBeInTheDocument();
        expect(screen.getByText('sess-slug-1')).toBeInTheDocument();
    });

    test('calls fetchMore when scrolling near the bottom with InfiniteScroll', async () => {
        const fetchMore = jest.fn();
        const { container } = renderInAppContext(
            <div className={MAIN_CONTENT_CLASSNAME}>
                <BulkSessionIngestionList
                    items={items}
                    totalCount={100}
                    loading={false}
                    fetchMore={fetchMore}
                />
            </div>
        );

        const mainContent = container.querySelector(
            `.${MAIN_CONTENT_CLASSNAME}`
        );
        if (mainContent) {
            fireEvent.scroll(mainContent, {
                target: { scrollY: 10000 },
            });
        }

        await waitFor(
            () => {
                expect(fetchMore).toHaveBeenCalled();
            },
            { timeout: 500 }
        );
    });

    test('passes correct props to InfiniteScroll component', () => {
        const fetchMore = jest.fn();
        const { container } = renderInAppContext(
            <BulkSessionIngestionList
                items={items}
                totalCount={1000}
                loading={false}
                fetchMore={fetchMore}
            />
        );

        const infiniteScroll = container.querySelector(
            '[data-testid="InfiniteScroll"]'
        );
        expect(infiniteScroll).toBeInTheDocument();
    });

    test('renders vendor label as link with service tier and vendor_id query param', () => {
        const vendorItems = [
            {
                id: 'ing-vendor-1',
                ingestionStatus: 'success',
                completedOn: null,
                bulkSession: {
                    id: 'sess-vendor-1',
                    slug: 'sess-vendor-slug-1',
                    downloadLink: null,
                    totalProducts: null,
                    createdBy: null,
                    label: {
                        __typename: 'Vendor',
                        name: 'Vendor Name',
                        serviceTier: {
                            __typename: 'ServiceTier',
                            displayName: 'Premium',
                        },
                        vendorId: 1234,
                    },
                },
            },
        ];

        renderInAppContext(
            <BulkSessionIngestionList
                items={vendorItems as never[]}
                totalCount={vendorItems.length}
                loading={false}
            />
        );

        const vendorLink = screen.getByRole('link', {
            name: 'Vendor Name (Premium)',
        });

        expect(vendorLink).toHaveAttribute(
            'href',
            `${OA_VENDOR_URL}?vendor_id=1234`
        );
    });

    test('does not render vendor link for subaccount labels', () => {
        renderInAppContext(
            <BulkSessionIngestionList
                items={items}
                totalCount={items.length}
                loading={false}
            />
        );

        expect(
            screen.queryByRole('link', { name: /\(.*\)/ })
        ).not.toBeInTheDocument();
    });
});
