import { fireEvent, screen } from '@testing-library/react';
import { renderInAppContext } from '@theorchard/suite-testing';
import dayjs from 'dayjs';
import {
    createEditFormDictionaries,
    createEditFormVendorData,
    getOaUserRolesMock,
    mockDate,
} from 'lib/tests/mock-data';
import React from 'react';
import * as features from 'shared/features';
import EditTable from '../edit-table';
import type { Props } from '../edit-table';

// Mock @theorchard/suite-icons
jest.mock('@theorchard/suite-icons', () => ({
    GlyphIcon: ({ name, size, className }: any) => (
        <span className={className} data-icon={name} data-size={size}>
            Icon
        </span>
    ),
}));

// Mock react-simple-wysiwyg Editor component
jest.mock('react-simple-wysiwyg', () => {
    const MockEditor = ({ value, onChange, style, children }: any) => (
        <>
            <textarea
                className="rsw-editor"
                value={value}
                onChange={(e: any) =>
                    onChange?.({ target: { value: e.target.value } })
                }
                style={style}
                data-testid="relationship-notes-editor"
            />
            {children}
        </>
    );

    return {
        __esModule: true,
        default: MockEditor,
        Editor: MockEditor,
        EditorProvider: ({ children }: any) => <div>{children}</div>,
        Toolbar: ({ children }: any) => <div>{children}</div>,
        BtnBold: () => <button>Bold</button>,
        BtnItalic: () => <button>Italic</button>,
        BtnUnderline: () => <button>Underline</button>,
        BtnStrikeThrough: () => <button>StrikeThrough</button>,
        BtnBulletList: () => <button>BulletList</button>,
        BtnNumberedList: () => <button>NumberedList</button>,
        BtnLink: () => <button>Link</button>,
        BtnClearFormatting: () => <button>ClearFormatting</button>,
        HtmlButton: () => <button>HTML</button>,
    };
});

const callBackFunc = jest.fn();

describe('<EditTable>', () => {
    afterAll(jest.resetAllMocks);

    const defaultProps = {
        roles: getOaUserRolesMock,
        labelData: createEditFormVendorData(),
        hasErrors: false,
        dictionaries: createEditFormDictionaries(),
        welcomeEmailDate: undefined,
        companyBrand: 'theorchard',
        setLabelData: callBackFunc,
        setVendorNoteData: callBackFunc,
        setVendorClosers: callBackFunc,
    } as unknown as Props;

    const renderComponent = (props: Partial<Props>) =>
        renderInAppContext(<EditTable {...defaultProps} {...props} />);

    describe('assignedTo test', () => {
        test('change assignedTo and check the updated value', () => {
            const { getByTestId } = renderComponent({});
            const field = getByTestId('assignedToId_select');
            expect(field).toHaveValue('1978');

            // Change the selected option
            fireEvent.change(field, {
                target: { value: '1979' },
            });

            // Assert that the selected option has changed);
            expect(field).toHaveValue('1979');
            const passedFunction = callBackFunc.mock.calls[0][0];
            expect(passedFunction(1)).toEqual({ assignedToId: 1979 });
        });
    });

    describe('welcomeEmailSend tests', () => {
        test('If welcomeEmailDate undefined it should be enabled', () => {
            const { getByTestId } = renderComponent({});
            const welcomeEmailSent = getByTestId('welcomeEmailDate');
            expect(welcomeEmailSent).not.toBeDisabled();
            expect(welcomeEmailSent).not.toBeChecked();
        });
        test('If welcomeEmailDate is exist then checkbox is disabled', () => {
            const { getByTestId } = renderComponent({
                welcomeEmailDate: mockDate,
            });
            const welcomeEmailSent = getByTestId('welcomeEmailDate');
            expect(welcomeEmailSent).toBeDisabled();
            expect(welcomeEmailSent).toBeChecked();
        });
        test('change welcomeEmailSend and check the updated value', () => {
            const { getByTestId } = renderComponent({});
            const welcomeEmailSent = getByTestId('welcomeEmailDate');
            fireEvent.click(welcomeEmailSent);
            expect(welcomeEmailSent).toBeChecked();
            const passedFunction = callBackFunc.mock.calls[1][0];
            expect(passedFunction(1)).toEqual({
                welcomeEmailSent: {
                    date: dayjs().format('YYYY-MM-DD'),
                    senderId: 'ed8474f8-8cd9-4fa8-ba72-5c91ba00570f',
                },
            });
        });
    });

    describe('serviceTier tests', () => {
        describe('serviceTier serviceTierUuid_select ff is on', () => {
            beforeEach(() => {
                jest.spyOn(
                    features,
                    'useIsEmployeeAbleToEditServiceTier'
                ).mockReturnValue(true);
            });
            // const { container } = renderComponent({});

            test('ServiceTier is not disabled with useIsEmployeeAbleToEditServiceTier ff turned on', () => {
                const { getByTestId } = renderComponent({});
                const serviceTierSelect = getByTestId('serviceTierUuid_select');
                expect(serviceTierSelect).not.toBeDisabled();
            });

            test('ServiceTier can be changed with ff turned on', () => {
                jest.spyOn(
                    features,
                    'useIsEmployeeAbleToEditServiceTier'
                ).mockReturnValue(true);
                const { getByTestId } = renderComponent({});
                const serviceTierSelect = getByTestId('serviceTierUuid_select');
                expect(serviceTierSelect).toHaveValue(
                    '5f2bd4fc-df94-4f35-97d3-ef23f8573279'
                );

                // Change the selected option
                fireEvent.change(serviceTierSelect, {
                    target: { value: '1ed7aac0-ceb6-4c09-9166-afda8f349316' },
                });

                // Assert that the selected option has changed);
                expect(serviceTierSelect).toHaveValue(
                    '1ed7aac0-ceb6-4c09-9166-afda8f349316'
                );
                const passedFunction = callBackFunc.mock.calls[2][0];
                expect(passedFunction(1)).toEqual({
                    serviceTierUuid: '1ed7aac0-ceb6-4c09-9166-afda8f349316',
                });
            });
        });

        describe('serviceTier serviceTierUuid_select ff is off', () => {
            beforeEach(() => {
                jest.spyOn(
                    features,
                    'useIsEmployeeAbleToEditServiceTier'
                ).mockReturnValue(false);
            });
            test('ServiceTier is disabled', () => {
                const { getByTestId } = renderComponent({});
                const serviceTierSelect = getByTestId('serviceTierUuid_select');
                expect(serviceTierSelect).toBeDisabled();
            });

            test('ServiceTier with awal brand can be cahnged', () => {
                const { getByTestId } = renderComponent({
                    companyBrand: 'awal',
                });
                const serviceTierSelect = getByTestId('serviceTierUuid_select');
                expect(serviceTierSelect).not.toBeDisabled();

                // Change the selected option
                fireEvent.change(serviceTierSelect, {
                    target: { value: '1ed7aac0-ceb6-4c09-9166-afda8f349316' },
                });

                // Assert that the selected option has changed);
                expect(serviceTierSelect).toHaveValue(
                    '1ed7aac0-ceb6-4c09-9166-afda8f349316'
                );
            });
        });
    });

    describe('owner tests', () => {
        test('the change in selected option', () => {
            const { getByTestId } = renderComponent({});
            const ownerSelect = getByTestId('owner_select');
            expect(ownerSelect).toHaveValue('1091 FT');

            // Change the selected option
            fireEvent.change(ownerSelect, {
                target: { value: 'two' },
            });
            // Assert that the selected option has changed);
            expect(ownerSelect).toHaveValue('two');
        });
        test('owner field is disabled', () => {
            const { getByTestId } = renderComponent({});
            const ownerSelect = getByTestId('owner_select');
            expect(ownerSelect).toBeDisabled();
        });
    });

    describe('parentCompany error message tests', () => {
        test('shows error message when parentCompanyUuid is missing and hasErrors is true', () => {
            const { getByText } = renderComponent({
                hasErrors: true,
                labelData: {
                    ...createEditFormVendorData(),
                    parentCompanyUuid: undefined,
                },
            });
            expect(
                getByText('Value is required. Specify company first')
            ).toBeInTheDocument();
        });

        test('does not show error message when parentCompanyUuid is present', () => {
            const { queryByText } = renderComponent({
                hasErrors: true,
                labelData: createEditFormVendorData(),
            });
            expect(
                queryByText('Value is required. Specify company first')
            ).not.toBeInTheDocument();
        });
    });

    describe('reviewContextNote tests', () => {
        test('reviewContextNotes can be changed with ff turned on', () => {
            const { getByTestId } = renderComponent({});
            const reviewContextNotes = getByTestId('reviewContextNotes');
            expect(reviewContextNotes).toHaveValue('');

            fireEvent.change(reviewContextNotes, {
                target: { value: 'this is a test note' },
            });
            expect(reviewContextNotes).toHaveValue('this is a test note');
        });
    });

    describe.each([
        [
            'company',
            'd25a4cd1-e820-45f2-be5c-56edcfeb8298',
            '77c6c150-19f3-451f-a692-1a5d7ef30e85',
        ],
        ['labelIdentifier', 'D3', 'FILM'],
        ['primaryGenreId', '1', '2'],
        ['countryId', '1', '2'],
        ['regionId', '1', '2'],
        ['defaultSalesSheetId', '2', '1'],
        ['productManagerId', '706', '1979'],
        ['quarterbackLabelManagerId', '1978', '1979'],
        ['owner', '1091 FT', 'two'],
    ])('Test for: %s', (fieldName, initValue, newValue) => {
        test(`Update ${fieldName} and check that value is correct`, () => {
            const { getByTestId } = renderComponent({});
            const field = getByTestId(fieldName + '_select');
            expect(field).toHaveValue(initValue);

            // Change the selected option
            fireEvent.change(field, {
                target: { value: newValue },
            });

            // Assert that the selected option has changed);
            expect(field).toHaveValue(newValue);
        });
    });

    describe('when isEmployeeShouldSeeSupportContactEmail is true', () => {
        beforeEach(() => {
            jest.spyOn(
                features,
                'useIsEmployeeShouldSeeSupportContactEmail'
            ).mockReturnValue(true);
        });

        test('it shows the supportContactEmail field and not the contactEmail field', () => {
            const { getByTestId, queryByTestId } = renderComponent({});
            const supportContactEmailField = getByTestId('supportContactEmail');
            const contactEmailField = queryByTestId('contactEmail');

            // Проверяем, что отображается поле supportContactEmail, а contactEmail отсутствует
            expect(supportContactEmailField).toBeInTheDocument();
            expect(supportContactEmailField).not.toBeDisabled();
            expect(contactEmailField).not.toBeInTheDocument();
        });
    });

    describe('when isEmployeeShouldSeeSupportContactEmail is false', () => {
        beforeEach(() => {
            jest.spyOn(
                features,
                'useIsEmployeeShouldSeeSupportContactEmail'
            ).mockReturnValue(false);
        });

        test('it shows the contactEmail field and not the supportContactEmail field', () => {
            const { getByTestId, queryByTestId } = renderComponent({});
            const contactEmailField = getByTestId('contactEmail');
            const supportContactEmailField = queryByTestId(
                'supportContactEmail'
            );

            // Проверяем, что отображается поле contactEmail, а supportContactEmail отсутствует
            expect(contactEmailField).toBeInTheDocument();
            expect(contactEmailField).not.toBeDisabled();
            expect(supportContactEmailField).not.toBeInTheDocument();
        });
    });

    describe('Account Info tests', () => {
        test('it shows the service type field', () => {
            const { getByTestId } = renderComponent({});
            const serviceTypeField = getByTestId('serviceTypeId_select');

            expect(serviceTypeField).toBeInTheDocument();
            expect(serviceTypeField).not.toBeDisabled();
        });

        test('it shows the closer multi select field', async () => {
            const { getByTestId } = renderComponent({ closers: ['1869'] });
            const closerMultiSelectField = getByTestId('closerMultiSelect');

            expect(closerMultiSelectField).not.toBeDisabled();
            const selectedClosers = await screen.findByText('AA No Closer');
            expect(selectedClosers).toBeInTheDocument();
        });

        test('it shows the statement period select field', async () => {
            const { getByTestId } = renderComponent({});
            const statementPeriodField = getByTestId('firstStatementPeriod');

            expect(statementPeriodField).toBeInTheDocument();
            expect(statementPeriodField).not.toBeDisabled();
        });
    });

    describe('Relationship Notes sanitization tests', () => {
        const mockSetRelationshipNotes = jest.fn();

        beforeEach(() => {
            mockSetRelationshipNotes.mockClear();
        });

        test('single <br> tag should be treated as empty', () => {
            const { getByTestId } = renderComponent({
                setRelationshipNotes: mockSetRelationshipNotes,
                relationshipNotes: '',
            });

            const editor = getByTestId('relationship-notes-editor');
            fireEvent.change(editor, { target: { value: '<br>' } });
            expect(mockSetRelationshipNotes).toHaveBeenCalledWith('');
        });

        test('all valid HTML content with allowed tags should be preserved', () => {
            const { getByTestId } = renderComponent({
                setRelationshipNotes: mockSetRelationshipNotes,
                relationshipNotes: '',
            });

            const editor = getByTestId('relationship-notes-editor');
            const content =
                'Plain text <b>Bold</b> <i>Italic</i> <u>Underline</u> <strike>Strike</strike><br>' +
                '<a href="https://example.com">Link</a><br>' +
                '<ol><li>Numbered 1</li><li>Numbered 2</li></ol>' +
                '<ul><li>Bullet 1</li><li>Bullet 2</li></ul>' +
                '<div>Div content</div><span>Span content</span>';

            fireEvent.change(editor, { target: { value: content } });
            expect(mockSetRelationshipNotes).toHaveBeenCalledWith(content);
        });

        test('paste handler preserves semantic HTML tags while sanitizing', () => {
            let insertedHtml = '';
            document.execCommand = jest.fn(
                (command: string, _showUI: boolean, value: string) => {
                    if (command === 'insertHTML') insertedHtml = value;
                    return true;
                }
            );

            const { container } = renderComponent({
                setRelationshipNotes: mockSetRelationshipNotes,
                relationshipNotes: '',
            });

            const editable = container.querySelector('[contenteditable]');
            if (editable) {
                const pasteHtml =
                    '<span style="font-weight: 700">Bold from Word</span>' +
                    '<b style="color: red">Bold with style</b>';

                const pasteEvent = new Event('paste', { bubbles: true });
                Object.defineProperty(pasteEvent, 'clipboardData', {
                    value: {
                        getData: (type: string) =>
                            type === 'text/html' ? pasteHtml : '',
                    },
                });

                fireEvent(editable, pasteEvent);

                expect(insertedHtml).toContain('<b>Bold from Word</b>');
                expect(insertedHtml).toContain('<b>Bold with style</b>');
            }
        });
    });
});
