import React from 'react';
import { render, fireEvent } from '@testing-library/react';
import { ModalFooter, Props } from '../modalFooter';

describe('<ModalFooter>', () => {
    const renderComponent = (props?: Partial<Props>) => render(<ModalFooter {...props} />);

    test('default rendering', () => {
        const { getByRole, getAllByRole } = renderComponent();
        expect(getAllByRole('button').length).toBe(1);
        const cancelButton = getByRole('button');
        expect(cancelButton).toBeVisible();
        expect(cancelButton).toHaveTextContent('cancel');
    });

    test('hideCancelButton hides cancel button', () => {
        const { queryByRole } = renderComponent({ hideCancelButton: true });
        expect(queryByRole('button')).toBeNull();
    });

    test('renders confirm button when onConfirm is passed', () => {
        const onConfirm = vi.fn();
        const { getAllByRole, getByText } = renderComponent({ onConfirm });

        const buttons = getAllByRole('button');
        expect(buttons.length).toBe(2);

        const confirm = getByText('save');
        expect(confirm).toBeVisible();
        if (confirm) fireEvent.click(confirm);
        expect(onConfirm).toHaveBeenCalled();
    });

    test('confirm button accepts custom title', () => {
        const onConfirm = vi.fn();
        const confirmTitle = 'CONFIRM TITLE';
        const { getByText } = renderComponent({ onConfirm, confirmTitle });
        const confirm = getByText(confirmTitle);
        expect(confirm).toBeVisible();
        if (confirm) fireEvent.click(confirm);
        expect(onConfirm).toHaveBeenCalled();
    });

    test('confirmDisabled disables confirm button', () => {
        const onConfirm = vi.fn();
        const { getByText } = renderComponent({
            onConfirm,
            confirmDisabled: true,
        });

        const confirm = getByText('save');
        expect(confirm).toBeVisible();
        expect(confirm).toBeDisabled();
    });

    describe('buttons override', () => {
        test('confirmButtonProps are passed through correctly', () => {
            const onConfirm = vi.fn();
            const confirmButtonProps = {
                title: 'Custom Confirm',
                variant: 'secondary' as const,
                loading: true,
                disabled: true,
                'data-testid': 'custom-confirm-button',
            };

            const r = renderComponent({
                onConfirm,
                confirmButtonProps,
            });

            const confirmButton = r.getByTestId('custom-confirm-button');

            expect(confirmButton).toBeVisible();
            expect(confirmButton).toBeDisabled();
            expect(confirmButton).toHaveClass('btn-secondary');
            expect(r.getByText('Custom Confirm')).toBeVisible();
        });

        test('cancelButtonProps are passed through correctly', () => {
            const onCancel = vi.fn();
            const cancelButtonProps = {
                title: 'Custom Cancel',
                variant: 'tertiary' as const,
                disabled: true,
                'data-testid': 'custom-cancel-button',
            };

            const r = renderComponent({
                onCancel,
                cancelButtonProps,
            });

            const cancelButton = r.getByTestId('custom-cancel-button');

            expect(cancelButton).toBeVisible();
            expect(cancelButton).toBeDisabled();
            expect(cancelButton).toHaveClass('btn-tertiary');
            expect(r.getByText('Custom Cancel')).toBeVisible();
        });

        test('confirmButtonProps onClick overrides onConfirm', () => {
            const onConfirm = vi.fn();
            const customOnClick = vi.fn();
            const confirmButtonProps = {
                onClick: customOnClick,
            };

            const r = renderComponent({
                onConfirm,
                confirmButtonProps,
            });

            const confirmButton = r.getByText('save');
            fireEvent.click(confirmButton);

            expect(customOnClick).toHaveBeenCalled();
            expect(onConfirm).not.toHaveBeenCalled();
        });

        test('cancelButtonProps onClick overrides onCancel', () => {
            const onCancel = vi.fn();
            const customOnClick = vi.fn();
            const cancelButtonProps = {
                onClick: customOnClick,
            };

            const r = renderComponent({
                onCancel,
                cancelButtonProps,
            });

            const cancelButton = r.getByText('cancel');
            fireEvent.click(cancelButton);

            expect(customOnClick).toHaveBeenCalled();
            expect(onCancel).not.toHaveBeenCalled();
        });

        test('confirmButtonProps title takes precedence over confirmTitle', () => {
            const onConfirm = vi.fn();
            const confirmButtonProps = {
                title: 'Button Props Title',
            };

            const r = renderComponent({
                onConfirm,
                confirmTitle: 'Legacy Title',
                confirmButtonProps,
            });

            expect(r.getByText('Button Props Title')).toBeVisible();
            expect(r.queryByText('Legacy Title')).toBeNull();
        });

        test('cancelButtonProps title takes precedence over cancelTitle', () => {
            const cancelButtonProps = {
                title: 'Button Props Cancel',
            };

            const r = renderComponent({
                cancelTitle: 'Legacy Cancel',
                cancelButtonProps,
            });

            expect(r.getByText('Button Props Cancel')).toBeVisible();
            expect(r.queryByText('Legacy Cancel')).toBeNull();
        });
    });

    describe('deprecated properties', () => {
        test('confirmVariant applies correct CSS class', () => {
            const onConfirm = vi.fn();
            const r = renderComponent({
                onConfirm,
                confirmVariant: 'danger',
                confirmButtonProps: { testId: 'confirm-button' },
            });

            const confirmButton = r.getByTestId('confirm-button');
            expect(confirmButton).toHaveClass('btn-danger');
        });

        test('cancelTitle sets custom cancel button text', () => {
            const cancelTitle = 'Custom Cancel Text';
            const { getByText } = renderComponent({ cancelTitle });

            expect(getByText(cancelTitle)).toBeVisible();
        });

        test('confirmVariant is overridden by confirmButtonProps.variant', () => {
            const onConfirm = vi.fn();
            const r = renderComponent({
                onConfirm,
                confirmVariant: 'danger',
                confirmButtonProps: { variant: 'success', testId: 'confirm-button' },
            });

            const confirmButton = r.getByTestId('confirm-button');
            expect(confirmButton).toHaveClass('btn-success');
            expect(confirmButton).not.toHaveClass('btn-danger');
        });
    });

    describe('className prop', () => {
        test('applies custom className to footer', () => {
            const customClass = 'custom-modal-footer';
            const { getByTestId } = renderComponent({ className: customClass });

            const footer = getByTestId('ModalFooter');
            expect(footer).toHaveClass(customClass);
            expect(footer).toHaveClass('ModalFooter');
            expect(footer).toHaveClass('ReactModal-footer');
        });

        test('works with multiple custom classes', () => {
            const customClasses = 'class1 class2 class3';
            const r = renderComponent({ className: customClasses });

            const footer = r.getByTestId('ModalFooter');
            expect(footer).toHaveClass('class1');
            expect(footer).toHaveClass('class2');
            expect(footer).toHaveClass('class3');
        });
    });

    describe('onCancel functionality', () => {
        test('onCancel is called when cancel button is clicked', () => {
            const onCancel = vi.fn();
            const r = renderComponent({ onCancel });

            const cancelButton = r.getByText('cancel');
            fireEvent.click(cancelButton);

            expect(onCancel).toHaveBeenCalledTimes(1);
            expect(onCancel).toHaveBeenCalledWith(expect.any(Object));
        });

        test('cancel button is rendered when onCancel is provided', () => {
            const onCancel = vi.fn();
            const r = renderComponent({ onCancel });

            expect(r.getAllByRole('button')).toHaveLength(1);
            expect(r.getByText('cancel')).toBeVisible();
        });

        test('cancel button works with custom cancelTitle', () => {
            const onCancel = vi.fn();
            const cancelTitle = 'Close Modal';
            const r = renderComponent({ onCancel, cancelTitle });

            const cancelButton = r.getByText(cancelTitle);
            fireEvent.click(cancelButton);

            expect(onCancel).toHaveBeenCalledTimes(1);
        });
    });

    describe('edge cases and combinations', () => {
        test('renders only confirm button when hideCancelButton is true and onConfirm is provided', () => {
            const onConfirm = vi.fn();
            const r = renderComponent({
                onConfirm,
                hideCancelButton: true,
            });

            expect(r.getAllByRole('button')).toHaveLength(1);
            expect(r.getByText('save')).toBeVisible();
            expect(r.queryByText('cancel')).toBeNull();
        });

        test('renders confirm button even without onConfirm when confirmButtonProps is provided', () => {
            const customOnClick = vi.fn();
            const r = renderComponent({
                confirmButtonProps: { onClick: customOnClick },
            });

            expect(r.getAllByRole('button')).toHaveLength(2);
            expect(r.getByText('save')).toBeVisible();
            expect(r.getByText('cancel')).toBeVisible();
        });

        test('both buttons work together with all custom properties', () => {
            const onConfirm = vi.fn();
            const onCancel = vi.fn();
            const r = renderComponent({
                onConfirm,
                onCancel,
                confirmTitle: 'Submit',
                cancelTitle: 'Abort',
                confirmDisabled: false,
                confirmVariant: 'success',
                confirmButtonProps: { testId: 'confirm-button' },
                cancelButtonProps: { testId: 'cancel-button' },
            });

            const confirmButton = r.getByTestId('confirm-button');
            const cancelButton = r.getByTestId('cancel-button');

            expect(confirmButton).toBeVisible();
            expect(confirmButton).toHaveClass('btn-success');
            expect(confirmButton).not.toBeDisabled();

            expect(cancelButton).toBeVisible();

            fireEvent.click(confirmButton);
            fireEvent.click(cancelButton);

            expect(onConfirm).toHaveBeenCalledTimes(1);
            expect(onCancel).toHaveBeenCalledTimes(1);
        });

        test('handles ReactNode titles correctly', () => {
            const confirmTitle = <span data-testid="custom-confirm">Custom Confirm</span>;
            const cancelTitle = <span data-testid="custom-cancel">Custom Cancel</span>;

            const r = renderComponent({
                onConfirm: vi.fn(),
                confirmTitle,
                cancelTitle,
            });

            expect(r.getByTestId('custom-confirm')).toBeVisible();
            expect(r.getByTestId('custom-cancel')).toBeVisible();
        });
    });

    describe('button size and default properties', () => {
        test('cancel button has default size lg', () => {
            const r = renderComponent({
                cancelButtonProps: { testId: 'cancel-button' },
            });

            const cancelButton = r.getByTestId('cancel-button');
            expect(cancelButton).toHaveClass('btn-lg');
        });

        test('confirm button has default size lg', () => {
            const onConfirm = vi.fn();
            const r = renderComponent({
                onConfirm,
                confirmButtonProps: { testId: 'confirm-button' },
            });

            const confirmButton = r.getByTestId('confirm-button');
            expect(confirmButton).toHaveClass('btn-lg');
        });

        test('cancel button has default variant quartenary', () => {
            const r = renderComponent({
                cancelButtonProps: { testId: 'cancel-button' },
            });

            const cancelButton = r.getByTestId('cancel-button');
            expect(cancelButton).toHaveClass('btn-quartenary');
        });

        test('confirm button has default variant primary', () => {
            const onConfirm = vi.fn();
            const r = renderComponent({
                onConfirm,
                confirmButtonProps: { testId: 'confirm-button' },
            });

            const confirmButton = r.getByTestId('confirm-button');
            expect(confirmButton).toHaveClass('btn-primary');
        });

        test('button sizes can be overridden via buttonProps', () => {
            const onConfirm = vi.fn();
            const r = renderComponent({
                onConfirm,
                confirmButtonProps: {
                    testId: 'confirm-btn',
                    size: 'sm',
                },
                cancelButtonProps: {
                    testId: 'cancel-btn',
                    size: 'lg',
                },
            });

            const confirmButton = r.getByTestId('confirm-btn');
            const cancelButton = r.getByTestId('cancel-btn');

            expect(confirmButton).toHaveClass('btn-sm');
            expect(confirmButton).not.toHaveClass('btn-lg');

            expect(cancelButton).toHaveClass('btn-lg');
            expect(cancelButton).not.toHaveClass('btn-sm');
        });
    });

    describe('button props merging', () => {
        test('additional props are passed to buttons', () => {
            const onConfirm = vi.fn();
            const r = renderComponent({
                onConfirm,
                confirmButtonProps: {
                    testId: 'confirm-btn',
                    'aria-label': 'Confirm action',
                },
                cancelButtonProps: {
                    testId: 'cancel-btn',
                    'aria-label': 'Cancel action',
                },
            });

            const confirmButton = r.getByTestId('confirm-btn');
            const cancelButton = r.getByTestId('cancel-btn');

            expect(confirmButton).toHaveAttribute('aria-label', 'Confirm action');
            expect(cancelButton).toHaveAttribute('aria-label', 'Cancel action');
        });

        test('loading state works correctly', () => {
            const onConfirm = vi.fn();
            const r = renderComponent({
                onConfirm,
                confirmButtonProps: { loading: true },
                cancelButtonProps: { loading: true },
            });

            const confirmButton = r.getByText('save');
            const cancelButton = r.getByText('cancel');

            expect(confirmButton).toBeDisabled();
            expect(cancelButton).toBeDisabled();
        });
    });
});
