import React from 'react';
import { render, screen } from '@testing-library/react';
import { PageContext } from '../..';
import { Sidecar } from '../index';
import { SidecarProps } from '../types';

describe('<Sidecar>', () => {
    const defaultProps = {
        onRequestClose: () => false,
        isOpen: true,
        header: 'Im a Sidecar!',
        closeTimeoutMS: 0,
    };

    const page = {
        className: 'TestPage',
    };

    const renderComponent = (props?: Partial<SidecarProps>) =>
        render(<Sidecar {...defaultProps} {...(props as SidecarProps)} />, {
            wrapper: ({ children }) => (
                <div className="TestPage PageContainer">
                    <PageContext.Provider value={page}>{children}</PageContext.Provider>
                </div>
            ),
        });

    describe('when closed', () => {
        test('renders nothing', () => {
            const { baseElement } = renderComponent({
                ...defaultProps,
                isOpen: false,
            });
            expect(baseElement).toMatchSnapshot();
        });
    });

    describe('when open', () => {
        test('renders modal', () => {
            const { baseElement } = renderComponent();
            expect(baseElement).toMatchSnapshot();
        });
    });

    describe('width', () => {
        test('by default is not defined', () => {
            renderComponent();
            const sidecar = screen.getByTestId('Modal');

            expect(sidecar).toBeVisible();
            expect(sidecar).not.toHaveAttribute('style');
        });

        test('is set on Modal content element', () => {
            renderComponent({ width: 400 });
            const sidecar = screen.getByTestId('Modal');

            expect(sidecar).toBeVisible();
            expect(sidecar).toHaveStyle({ '--sidecar-width': '400px' });
        });

        test('is minimum 340px', () => {
            renderComponent({ width: 300 });
            const sidecar = screen.getByTestId('Modal');

            expect(sidecar).toBeVisible();
            expect(sidecar).toHaveStyle({ '--sidecar-width': '340px' });
        });
    });

    test('renders as sidecar variant', () => {
        const r = renderComponent();
        const portal = r.baseElement.querySelector('.ReactModalPortal-Sidecar');
        expect(portal).toBeInTheDocument();
    });

    describe('footer inheritance from Modal', () => {
        test('does not render footer by default', () => {
            const r = renderComponent();
            expect(r.queryByTestId('ModalFooter')).toBeNull();
        });

        test('renders footer when confirmButtonProps is passed', () => {
            const r = renderComponent({
                confirmButtonProps: { title: 'Apply' },
            });
            expect(r.getByTestId('ModalFooter')).toBeInTheDocument();
            expect(r.getByText('Apply')).toBeVisible();
            expect(r.getByText('cancel')).toBeVisible();
        });

        test('customizes buttons with buttonProps', () => {
            const r = renderComponent({
                confirmButtonProps: {
                    title: 'Save Changes',
                    variant: 'quartenary',
                    disabled: true,
                },
                cancelButtonProps: {
                    title: 'Discard',
                    variant: 'danger',
                },
            });

            const confirmBtn = r.getByRole('button', { name: 'Save Changes' });
            const cancelBtn = r.getByRole('button', { name: 'Discard' });

            expect(confirmBtn).toBeVisible();
            expect(confirmBtn).toHaveClass('btn-quartenary');
            expect(confirmBtn).toBeDisabled();

            expect(cancelBtn).toBeVisible();
            expect(cancelBtn).toHaveClass('btn-danger');
        });

        test('buttonProps override deprecated Modal props', () => {
            const r = renderComponent({
                confirmTitle: 'Old Save',
                confirmVariant: 'primary',
                cancelTitle: 'Old Cancel',
                confirmButtonProps: {
                    title: 'New Save',
                    variant: 'quartenary',
                },
                cancelButtonProps: {
                    title: 'New Cancel',
                    variant: 'secondary',
                },
            });

            const confirmBtn = r.getByRole('button', { name: 'New Save' });
            const cancelBtn = r.getByRole('button', { name: 'New Cancel' });

            expect(confirmBtn).toBeVisible();
            expect(confirmBtn).toHaveClass('btn-quartenary');
            expect(cancelBtn).toBeVisible();
            expect(cancelBtn).toHaveClass('btn-secondary');

            expect(r.queryByText('Old Save')).toBeNull();
            expect(r.queryByText('Old Cancel')).toBeNull();
        });

        test('handles mixed deprecated and new props', () => {
            const r = renderComponent({
                confirmTitle: 'Fallback Title',
                confirmDisabled: true,
                confirmButtonProps: {
                    variant: 'quartenary',
                },
            });

            const btn = r.getByRole('button', { name: 'Fallback Title' });
            expect(btn).toBeVisible();
            expect(btn).toHaveClass('btn-quartenary');
            expect(btn).toBeDisabled();
            expect(r.getByText('Fallback Title')).toBeVisible();
        });

        test('handles onClick in buttonProps', () => {
            const handleConfirm = vi.fn();
            const handleCancel = vi.fn();
            const r = renderComponent({
                confirmButtonProps: {
                    title: 'Apply',
                    testId: 'confirm-button',
                    onClick: handleConfirm,
                },
                cancelButtonProps: {
                    title: 'Cancel',
                    testId: 'cancel-button',
                    onClick: handleCancel,
                },
            });

            const confirmBtn = r.getByTestId('confirm-button');
            const cancelBtn = r.getByTestId('cancel-button');

            confirmBtn.click();
            cancelBtn.click();

            expect(handleConfirm).toHaveBeenCalledTimes(1);
            expect(handleCancel).toHaveBeenCalledTimes(1);
        });
    });
});
