import React from 'react';
import { render, fireEvent } from '@testing-library/react';
import { testComponent } from 'lib/test-utils/common';
import { GlyphToggle } from '../glyphToggle';
import type { GlyphToggleProps } from '../glyphToggle';

describe('<GlyphToggle>', () => {
    const defaultProps: GlyphToggleProps = {
        defaultValue: false,
        onChange: vi.fn(),
        tooltip: 'This is my favorite song!',
        name: 'starred',
        size: 24,
    };

    const renderComponent = (customProps?: Partial<GlyphToggleProps>) => {
        const props = { ...defaultProps, ...customProps } as GlyphToggleProps;

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

    testComponent(GlyphToggle);

    test('applies style', () => {
        const { getByTestId } = renderComponent({ style: { marginTop: 10 } });
        expect(getByTestId('GlyphToggle')).toHaveStyle({ marginTop: '10px' });
    });

    afterEach(() => {
        vi.resetAllMocks();
    });

    test('renders its default no-toggled state', () => {
        const { getByTestId } = renderComponent();

        const btn = getByTestId('GlyphToggle');
        expect(btn).not.toHaveClass('toggled');
        expect(getByTestId('NotStarredGlyphIcon')).toBeInTheDocument();
    });

    test('renders with expected initial state from defaultValue prop', () => {
        const { getByTestId } = renderComponent({ defaultValue: true });

        const btn = getByTestId('GlyphToggle');
        expect(btn).toHaveClass('toggled');
        expect(getByTestId('StarredGlyphIcon')).toBeInTheDocument();
    });

    test('renders with controlled state from value prop', () => {
        const { getByTestId } = renderComponent({
            value: false,
        });

        const btn = getByTestId('GlyphToggle');
        expect(btn).not.toHaveClass('toggled');
    });

    test('toggles its own class on click and calls onChange callback with the new state', () => {
        const { getByTestId } = renderComponent({ defaultValue: true });

        const btn = getByTestId('GlyphToggle');
        expect(btn).toHaveClass('toggled');

        fireEvent.click(btn);

        expect(defaultProps.onChange).toHaveBeenCalledWith(false);
        expect(btn).not.toHaveClass('toggled');
        expect(getByTestId('NotStarredGlyphIcon')).toBeInTheDocument();
    });

    test('renders with expected tooltip on hover', async () => {
        const { getByTestId, findByText } = renderComponent({
            tooltip: 'This is my favorite song!',
        });

        const btn = getByTestId('GlyphToggle');
        fireEvent.mouseOver(btn);

        const tooltipText = await findByText('This is my favorite song!');

        expect(tooltipText).toBeInTheDocument();
    });

    test('renders and calls onChange with the new state when controlled', () => {
        const { getByTestId } = renderComponent({
            value: true,
        });

        const btn = getByTestId('GlyphToggle');
        expect(btn).toHaveClass('toggled');

        fireEvent.click(btn);
        expect(defaultProps.onChange).toHaveBeenCalledWith(false);
    });

    test('renders a disabled state that wont toggle on click', () => {
        const { getByTestId } = renderComponent({
            disabled: true,
        });

        const btn = getByTestId('GlyphToggle');
        expect(btn).toHaveClass('disabled');

        fireEvent.click(btn);
        expect(defaultProps.onChange).not.toHaveBeenCalled();
    });
});
