import React from 'react';
import { within } from '@testing-library/react';
import { renderInAppContext } from '@theorchard/suite-testing';
import { kebabCase } from 'lodash-es';
import { CLASSNAME } from '../constants';
import { PageHeader } from '../index';

interface CommonProps {
    className?: string;
    testId?: string;
    children?: React.ReactNode;
}

function testHeaderComponent<T>(Component: React.FC<CommonProps & T>, componentClassName: string) {
    const componentTestId = Component.displayName ?? Component.name;
    const renderComponent = (props?: CommonProps) =>
        renderInAppContext(<Component {...(props as CommonProps & T)} />);

    test('has className', () => {
        const { container } = renderComponent();
        const root = container.querySelector(`.${componentClassName}`);

        expect(root).toBeVisible();
    });

    test('has testId', () => {
        const { getByTestId } = renderComponent();
        const root = getByTestId(componentTestId);

        expect(root).toBeVisible();
    });

    test('accepts "className"', () => {
        const className = 'my-class';
        const { container } = renderComponent({ className });
        const root = container.querySelector(`.${componentClassName}`);

        expect(root).toBeVisible();
        expect(root).toHaveClass(className);
    });

    test('accepts "testId"', () => {
        const testId = 'test';
        const { getByTestId } = renderComponent({ testId });
        const root = getByTestId(testId);

        expect(root).toBeVisible();
    });

    test('renders children', () => {
        const contentTestId = 'ContentTestId';
        const content = <div data-testid={contentTestId}>Content!</div>;
        const { getByTestId } = renderComponent({ children: content });

        const childContent = getByTestId(contentTestId);
        expect(childContent).toBeVisible();
    });
}

describe('PageHeader', () => {
    testHeaderComponent(PageHeader, CLASSNAME);

    const subComponents = [
        'Breadcrumb',
        'ExternalLinks',
        'Description',
        'Primary',
        'Secondary',
        'Tertiary',
    ];

    describe.each(subComponents)('%s', (name) => {
        const Component = (PageHeader as unknown as Record<string, React.FC>)[name];

        test('is defined', () => {
            expect(Component).toBeDefined();
        });

        testHeaderComponent(Component, `${CLASSNAME}-${kebabCase(name)}`);
    });

    test('applies style', () => {
        const testId = 'page-header-style';
        const { getByTestId } = renderInAppContext(
            <PageHeader testId={testId} style={{ marginTop: 10 }}>
                <div>Content</div>
            </PageHeader>
        );

        expect(getByTestId(testId)).toHaveStyle({ marginTop: '10px' });
    });

    test('sets variant class', () => {
        const testId = 'SOME-TEST-ID';
        const contentTestId = 'ContentTestId';
        const content = <div data-testid={contentTestId}>Content!</div>;
        const { getByTestId } = renderInAppContext(
            <PageHeader testId={testId} variant="standalone">
                {content}
            </PageHeader>
        );

        const pageHeader = getByTestId(testId);
        expect(pageHeader).toHaveClass('SuitePageHeader-standalone');
    });

    test('renders with loading breadcrumb item', () => {
        const breadcrumbs = [
            {
                label: 'Not Loading',
                loading: false,
            },
            {
                label: 'Loading',
                loading: true,
            },
        ];

        const { getByRole } = renderInAppContext(
            <PageHeader breadcrumbs={breadcrumbs} mainContent={{ title: 'Test Title' }} />
        );

        const lastBreadcrumb = getByRole('listitem', { current: 'page' });
        expect(within(lastBreadcrumb).getByTestId('SkeletonLoader')).toBeInTheDocument();
    });

    describe('coverArt props', () => {
        test('renders coverArt with loading state using coverArt new extended props', () => {
            const { container } = renderInAppContext(
                <PageHeader
                    coverArt={{
                        url: 'test-image.jpg',
                        loading: true,
                        shape: 'round',
                    }}
                >
                    Content
                </PageHeader>
            );

            expect(container.querySelector('.CoverArt')).toBeInTheDocument();
            expect(container.querySelector('.CoverArt.round')).toBeInTheDocument();
            expect(container.querySelector('.SkeletonLoader')).toBeInTheDocument();
        });

        test('works with legacy coverArt props only', () => {
            const { container } = renderInAppContext(
                <PageHeader coverArt={{ url: 'legacy-image.jpg', shape: 'landscape' }}>
                    Content
                </PageHeader>
            );

            const img = container.querySelector('img');
            expect(img).toHaveAttribute('src', 'legacy-image.jpg');
            expect(container.querySelector('.CoverArt.landscape')).toBeInTheDocument();
            expect(container.querySelector('.SkeletonLoader')).not.toBeInTheDocument();
        });
    });

    // Test the new unified pattern (no children + mainContent = unified header)
    describe('unified pattern', () => {
        test('renders unified header when no children and mainContent provided', () => {
            const { container, getAllByText } = renderInAppContext(
                <PageHeader
                    mainContent={{ title: 'Unified Test Title' }}
                    testId="unified-test"
                    sticky
                />
            );

            // Should render the unified header structure (dual headers: main + sticky)
            expect(getAllByText('Unified Test Title')).toHaveLength(2);
            expect(container.querySelector('.SuitePageHeader-unified')).toBeInTheDocument();

            // Should use the unified testId (appears on both main and sticky header)
            expect(container.querySelectorAll('[data-testid="unified-test"]')).toHaveLength(2);
        });

        test('renders traditional header when children provided (backward compatibility)', () => {
            const { container, getByText } = renderInAppContext(
                <PageHeader testId="traditional-test">
                    <div>Traditional Content</div>
                </PageHeader>
            );

            // Should render traditional structure with children
            expect(getByText('Traditional Content')).toBeInTheDocument();
            expect(container.querySelector('.SuitePageHeader')).toBeInTheDocument();

            // Should NOT render unified structure
            expect(container.querySelector('.SuitePageHeader-unified')).not.toBeInTheDocument();

            // Should use the traditional testId
            expect(container.querySelector('[data-testid="traditional-test"]')).toBeInTheDocument();
        });
    });
});
