import React, { useEffect, useRef } from 'react';
import { fireEvent, render, screen } from '@testing-library/react';
import { StoreIcon } from '@theorchard/suite-icons';
import { Checkbox, CheckboxProps } from '../checkbox';

describe('<Checkbox>', () => {
    const renderComponent = (props: Partial<CheckboxProps> = {}) => {
        const { getByRole } = render(<Checkbox onChange={vi.fn()} {...props} />);

        return getByRole('checkbox');
    };

    test('accepts icon', () => {
        const icon = <StoreIcon name="facebook" size="16" testId="facebook-test-id" />;

        render(<Checkbox icon={icon} />);

        expect(screen.getByTestId('facebook-test-id')).toBeVisible();
    });

    test('accepts tooltip', () => {
        render(<Checkbox tooltip={{ size: 16, message: 'test message', id: 'tooltip-test-id' }} />);

        expect(screen.getByTestId('Tooltip')).toBeVisible();
    });

    test('renders with expected tooltip on hover', async () => {
        const renderComponent = (customProps?: Partial<CheckboxProps>) => {
            const defaultProps: CheckboxProps = {
                id: 'hoverMe',
                testId: 'tooltip-hoverMe',
                tooltip: { size: 16, message: 'Testing text tooltip', id: 'tooltip-test-id' },
            };
            const props = { ...defaultProps, ...customProps };

            return render(<Checkbox {...props} />);
        };

        const { findByText, getByTestId } = renderComponent();

        const tooltipBase = getByTestId('Tooltip');
        fireEvent.mouseOver(tooltipBase);

        const tooltipPopover = await findByText('Testing text tooltip');
        expect(tooltipPopover).toBeInTheDocument();
    });

    test('accepts ref', () => {
        const ParentComponent = () => {
            const ref = useRef<HTMLInputElement>(null);

            useEffect(() => {
                if (ref.current) ref.current.checked = true;
            });

            return <Checkbox ref={ref} />;
        };

        const { getByRole } = render(<ParentComponent />);
        const element = getByRole('checkbox');

        expect(element).toBeChecked();
    });

    describe('unchecked', () => {
        test('checkbox is unchecked', () => {
            const element = renderComponent({ checked: false });

            expect(element).not.toBeChecked();
            expect(element).not.toBePartiallyChecked();
        });

        test('has default class names', () => {
            const element = renderComponent({ checked: false });

            expect(element.parentElement?.className).toEqual('FormCheckbox form-check');
        });
    });

    describe('checked', () => {
        test('checkbox is checked', () => {
            const element = renderComponent({ checked: true });

            expect(element).toBeChecked();
            expect(element).not.toBePartiallyChecked();
        });

        test('has "checked" class name', () => {
            const element = renderComponent({ checked: true });

            expect(element.parentElement?.className).toEqual('FormCheckbox checked form-check');
        });
    });

    describe('indeterminate', () => {
        test('checkbox is indeterminate', () => {
            const element = renderComponent({ indeterminate: true });

            expect(element).not.toBeChecked();
            expect(element).toBePartiallyChecked();
        });

        test('has "indeterminate" class name', () => {
            const element = renderComponent({ indeterminate: true });

            expect(element.parentElement?.className).toEqual(
                'FormCheckbox indeterminate form-check'
            );
        });
    });

    describe('colorIndex', () => {
        const colorIndex = 3;

        test('sets color color variable on element', () => {
            const element = renderComponent({
                checked: true,
                colorIndex,
            }).parentElement;

            expect(element).toHaveStyle({
                ['--checkbox-base']: 'var(--data-3)',
                ['--checkbox-hover']: 'hsl(from var(--checkbox-base) h s calc(l - 10))',
            });
        });

        test('does not set style by default', () => {
            const element = renderComponent().parentElement;

            expect(element).not.toHaveAttribute('style');
        });
    });

    describe('with "customColor"', () => {
        test('applies custom color', () => {
            const customColor = '#00FFFF';
            const element = renderComponent({ customColor }).parentElement;

            expect(element).toHaveStyle(
                '--checkbox-base: #00FFFF; --checkbox-hover: hsl(from var(--checkbox-base) h s calc(l - 10));'
            );
        });
    });

    describe('with locked', () => {
        const renderLockedComponent = (props: Partial<CheckboxProps> = {}) => {
            const { getByTestId } = render(
                <Checkbox onChange={vi.fn()} testId="FormCheckbox" {...props} />
            );

            return getByTestId('FormCheckbox');
        };

        test('shows lock glyph in place of input', () => {
            renderLockedComponent({ locked: true }).parentElement;

            expect(screen.queryByRole('checkbox')).toBeNull();
            expect(screen.getByTestId('LockGlyphIcon')).toBeInTheDocument();
        });

        test('renders label', () => {
            renderLockedComponent({ locked: true, label: 'test-label', icon: <div>icon</div> })
                .parentElement;

            expect(screen.getByText('test-label')).toBeInTheDocument();
            expect(screen.getByText('icon')).toBeInTheDocument();
        });

        test('has correct class name', () => {
            const element = renderLockedComponent({ locked: true, className: 'test-class' });

            expect(element).toHaveClass('test-class');
            expect(element).toHaveClass('FormCheckbox');
            expect(element).toHaveClass('form-check');
        });
    });
});
