import React from 'react';
import type { TextInput } from 'react-native';
import { fireEvent, render, screen } from '@testing-library/react-native';
import FreeTextBox from '../FreeTextBox';
import themes from '../../../branding/themes';
import { BASE_THEME } from '../../../branding/constants/themes';
import useTheme from '../../../branding/hooks/useTheme';

jest.mock('../../../branding/hooks/useTheme', () => ({
    __esModule: true,
    default: jest.fn()
}));

const currentTheme = themes[BASE_THEME];
const mockedUseTheme = useTheme as unknown as jest.Mock;

describe('FreeTextBox', () => {
    const label = 'Additional Details (Required)';
    const placeholder = 'Add details...';

    beforeEach(() => {
        mockedUseTheme.mockImplementation(() => ({
            ...currentTheme,
            theme: BASE_THEME
        }));
    });

    afterEach(() => {
        jest.clearAllMocks();
    });

    it('always renders the label above the box, even when empty', () => {
        render(
            <FreeTextBox
                label={label}
                value=""
                onChangeText={jest.fn()}
                placeholder={placeholder}
            />
        );

        expect(screen.getByText(label)).toBeTruthy();
    });

    it('shows the placeholder when empty', () => {
        render(
            <FreeTextBox
                label={label}
                value=""
                onChangeText={jest.fn()}
                placeholder={placeholder}
            />
        );

        expect(screen.getByPlaceholderText(placeholder)).toBeTruthy();
    });

    it('renders the typed value when populated', () => {
        render(
            <FreeTextBox
                label={label}
                value="Great show, needs a louder mix."
                onChangeText={jest.fn()}
                placeholder={placeholder}
            />
        );

        expect(
            screen.getByDisplayValue('Great show, needs a louder mix.')
        ).toBeTruthy();
    });

    it('calls onChangeText as the user types', () => {
        const onChangeText = jest.fn();
        render(
            <FreeTextBox
                label={label}
                value=""
                onChangeText={onChangeText}
                placeholder={placeholder}
            />
        );

        fireEvent.changeText(screen.getByTestId('freeTextBoxInput'), 'A note');

        expect(onChangeText).toHaveBeenCalledWith('A note');
    });

    it('invokes the focus and blur callbacks as the field gains and loses focus', () => {
        const onFocus = jest.fn();
        const onBlur = jest.fn();
        render(
            <FreeTextBox
                label={label}
                value=""
                onChangeText={jest.fn()}
                placeholder={placeholder}
                onFocus={onFocus}
                onBlur={onBlur}
            />
        );

        const input = screen.getByTestId('freeTextBoxInput');
        fireEvent(input, 'focus');
        expect(onFocus).toHaveBeenCalled();

        fireEvent(input, 'blur');
        expect(onBlur).toHaveBeenCalled();
    });

    it('blurs the field on return so the keyboard dismisses without a newline', () => {
        const ref = React.createRef<TextInput>();
        render(
            <FreeTextBox
                ref={ref}
                label={label}
                value=""
                onChangeText={jest.fn()}
                placeholder={placeholder}
            />
        );

        const blurSpy = jest.spyOn(ref.current as TextInput, 'blur');
        fireEvent(screen.getByTestId('freeTextBoxInput'), 'submitEditing');

        expect(blurSpy).toHaveBeenCalled();
    });

    it('matches the snapshot', () => {
        render(
            <FreeTextBox
                label={label}
                value=""
                onChangeText={jest.fn()}
                placeholder={placeholder}
            />
        );

        expect(screen.toJSON()).toMatchSnapshot();
    });
});
