import { render, screen, waitFor, fireEvent , act } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import MockAppWithProviders from "../../../../../../mocks/AppWithProvider";
import ChangePasswordForm from "@/components/dashboard/change-password/change-password-form";
import {SET_USER_PASSWORD} from "@/core/data/apiRoutes";
import {server} from "../../../../../../mocks/server";
import {rest} from "msw";

describe('Change Password Form Component From Change Password Page', () => {
    describe('Rendering', () => {
        it('Should see change password heading',() => {
            render(<MockAppWithProviders><ChangePasswordForm /></MockAppWithProviders>);
            const changePasswordElement = screen.getByRole('heading', { level: 4 });
            expect(changePasswordElement).toHaveTextContent('تغییر رمز عبور');
        });
        it('Should see the label for current password field', () => {
            render(<MockAppWithProviders><ChangePasswordForm /></MockAppWithProviders>);
            const currentPasswordLabel = screen.queryByLabelText('رمز عبور فعلی');
            expect(currentPasswordLabel).toBeInTheDocument();
        });
        it('Should see the label for new password field', () => {
            render(<MockAppWithProviders><ChangePasswordForm /></MockAppWithProviders>);
            const newPasswordLabel = screen.queryByLabelText('رمز عبور جدید');
            expect(newPasswordLabel).toBeInTheDocument();
        });
        it('Should see the label for confirm password field', () => {
            render(<MockAppWithProviders><ChangePasswordForm /></MockAppWithProviders>);
            const confirmPasswordLabel = screen.queryByLabelText('تکرار رمز عبور جدید');
            expect(confirmPasswordLabel).toBeInTheDocument();
        });
        it('Should see the submit button with the submit label and should be disable', () => {
            render(<MockAppWithProviders><ChangePasswordForm /></MockAppWithProviders>);
            const submitButton = screen.getByRole('button', { name: 'ثبت' });
            expect(submitButton).toBeInTheDocument();
            expect(submitButton).toBeDisabled();
        });
        it('Should have empty input fields and not see any validation error for current password, new password, and confirm password', () => {
            render(<MockAppWithProviders><ChangePasswordForm /></MockAppWithProviders>);
            const currentPasswordInput = screen.queryByLabelText('رمز عبور فعلی');
            const newPasswordInput = screen.queryByLabelText('رمز عبور جدید');
            const confirmPasswordInput = screen.queryByLabelText('تکرار رمز عبور جدید');

            expect(currentPasswordInput).toHaveValue('');
            expect(newPasswordInput).toHaveValue('');
            expect(confirmPasswordInput).toHaveValue('');

            expect(screen.queryByText("وارد کردن رمز عبور فعلی الزامیست!")).not.toBeInTheDocument();
            expect(screen.queryByText("وارد کردن رمز عبور جدید الزامیست!")).not.toBeInTheDocument();
            expect(screen.queryByText("وارد کردن تکرار رمز عبور جدید الزامیست!")).not.toBeInTheDocument();

        });
    });
    describe("Behavior", ()=>{
        it('Should fill the current password field and not see any error while its not empty', async () => {
            render(<MockAppWithProviders><ChangePasswordForm /></MockAppWithProviders>);

            const currentPasswordInput = screen.queryByLabelText('رمز عبور فعلی');

            // Simulate typing something in the current password input
            fireEvent.change(currentPasswordInput, { target: { value: 'witel@fani0' } });

            await waitFor(() => {
                expect(screen.queryByText("وارد کردن رمز عبور فعلی الزامیست!")).not.toBeInTheDocument();
                expect(currentPasswordInput).toHaveValue('witel@fani0');
            });
        });
        it('Should fill the new password field and not see any error while its not empty', async () => {
            render(<MockAppWithProviders><ChangePasswordForm /></MockAppWithProviders>);

            const newPasswordInput = screen.queryByLabelText('رمز عبور جدید');

            // Simulate typing something in the new password input
            fireEvent.change(newPasswordInput, { target: { value: 'witel@fani1' } });

            await waitFor(() => {
                expect(screen.queryByText("وارد کردن رمز عبور جدید الزامیست!")).not.toBeInTheDocument();
                expect(newPasswordInput).toHaveValue('witel@fani1');
            });
        });
        it('Should fill the confirm new password field and not see any error while its not empty', async () => {
            render(<MockAppWithProviders><ChangePasswordForm /></MockAppWithProviders>);

            const confirmPasswordInput = screen.queryByLabelText('تکرار رمز عبور جدید');

            // Simulate typing something in the confirmation new password input
            fireEvent.change(confirmPasswordInput, { target: { value: 'witel@fani1' } });

            await waitFor(() => {
                expect(screen.queryByText("وارد کردن تکرار رمز عبور جدید الزامیست!")).not.toBeInTheDocument();
                expect(confirmPasswordInput).toHaveValue('witel@fani1');
            });
        });
    });
    describe("Validation", ()=>{
        it('Should see error while current password is empty on blur event', async () => {
            render(<MockAppWithProviders><ChangePasswordForm /></MockAppWithProviders>);

            // Simulate blur event on the current password input
            const currentPasswordInput = screen.queryByLabelText('رمز عبور فعلی');

            // Clear the input field
            fireEvent.change(currentPasswordInput, { target: { value: '' } });

            fireEvent.blur(currentPasswordInput);

            await waitFor(()=>{
                expect(screen.queryByText("وارد کردن رمز عبور فعلی الزامیست!")).toBeInTheDocument()
            });
        });
        it('Should see error while new password is empty on blur event', async () => {
            render(<MockAppWithProviders><ChangePasswordForm /></MockAppWithProviders>);

            // Simulate blur event on the new password input
            const newPasswordInput = screen.queryByLabelText('رمز عبور جدید');

            // Clear the input field
            fireEvent.change(newPasswordInput, { target: { value: '' } });

            fireEvent.blur(newPasswordInput);

            await waitFor(()=>{
                expect(screen.queryByText("وارد کردن رمز عبور جدید الزامیست!")).toBeInTheDocument()
            });
        });
        it('Should see error while confirm new password is empty on blur event', async () => {
            render(<MockAppWithProviders><ChangePasswordForm /></MockAppWithProviders>);

            // Simulate blur event on the new password input
            const confirmPasswordInput = screen.queryByLabelText('تکرار رمز عبور جدید');

            // Clear the input field
            fireEvent.change(confirmPasswordInput, { target: { value: '' } });

            fireEvent.blur(confirmPasswordInput);

            await waitFor(()=>{
                expect(screen.queryByText("وارد کردن تکرار رمز عبور جدید الزامیست!")).toBeInTheDocument()
            });
        });
        it('Should see error when new password is less than 8 characters', async () => {
            render(<MockAppWithProviders><ChangePasswordForm /></MockAppWithProviders>);

            const newPasswordInput = screen.queryByLabelText('رمز عبور جدید');
            const submitButton = screen.getByRole('button', { name: 'ثبت' });

            // Simulate entering a short new password
            fireEvent.change(newPasswordInput, { target: { value: 'test' } });
            fireEvent.blur(newPasswordInput);

            await waitFor(() => {
                expect(screen.queryByText("رمز عبور باید حداقل 8 کاراکتر باشد.")).toBeInTheDocument();
            });

            // Simulate clicking the submit button
            fireEvent.click(submitButton);

            await waitFor(() => {
                expect(screen.queryByText("رمز عبور باید حداقل 8 کاراکتر باشد.")).toBeInTheDocument();
            });
        });
        it('Should not see error when new password are 8 or more characters', async () => {
            render(<MockAppWithProviders><ChangePasswordForm /></MockAppWithProviders>);

            const newPasswordInput = screen.queryByLabelText('رمز عبور جدید');
            const submitButton = screen.getByRole('button', { name: 'ثبت' });

            // Simulate entering a valid new password
            fireEvent.change(newPasswordInput, { target: { value: 'Witel@fani1' } });
            fireEvent.blur(newPasswordInput);

            await waitFor(() => {
                expect(screen.queryByText("رمز عبور باید حداقل 8 کاراکتر باشد.")).not.toBeInTheDocument();
            });

            // Simulate clicking the submit button
            fireEvent.click(submitButton);

            await waitFor(() => {
                expect(screen.queryByText("رمز عبور باید حداقل 8 کاراکتر باشد.")).not.toBeInTheDocument();
            });
        });
        it('Should see error when new password and confirm password do not match on blur event and submit click', async () => {
            render(<MockAppWithProviders><ChangePasswordForm /></MockAppWithProviders>);

            const newPasswordInput = screen.queryByLabelText('رمز عبور جدید');
            const confirmPasswordInput = screen.queryByLabelText('تکرار رمز عبور جدید');
            const submitButton = screen.getByRole('button', { name: 'ثبت' });

            // Simulate entering a valid new password
            fireEvent.change(newPasswordInput, { target: { value: 'Witel@fani1' } });
            fireEvent.blur(newPasswordInput);

            // Simulate entering a different value in the confirm password field
            fireEvent.change(confirmPasswordInput, { target: { value: 'MismatchedPassword' } });
            fireEvent.blur(confirmPasswordInput);

            await waitFor(() => {
                expect(screen.queryByText("پسورد و تکرار رمز عبور باید یکسان باشد")).toBeInTheDocument();
            });

            // Simulate clicking the submit button
            fireEvent.click(submitButton);

            await waitFor(() => {
                expect(screen.queryByText("پسورد و تکرار رمز عبور باید یکسان باشد")).toBeInTheDocument();
            });
        });
        it('Should not see error when new password and confirm password match on blur event and submit click', async () => {
            render(<MockAppWithProviders><ChangePasswordForm /></MockAppWithProviders>);

            const newPasswordInput = screen.queryByLabelText('رمز عبور جدید');
            const confirmPasswordInput = screen.queryByLabelText('تکرار رمز عبور جدید');
            const submitButton = screen.getByRole('button', { name: 'ثبت' });

            // Simulate entering a valid new password
            fireEvent.change(newPasswordInput, { target: { value: 'Witel@fani1' } });
            fireEvent.blur(newPasswordInput);

            // Simulate entering the same value in the confirmation password field
            fireEvent.change(confirmPasswordInput, { target: { value: 'Witel@fani1' } });
            fireEvent.blur(confirmPasswordInput);

            await waitFor(() => {
                expect(screen.queryByText("پسورد و تکرار رمز عبور باید یکسان باشد")).not.toBeInTheDocument();
            });

            // Simulate clicking the submit button
            fireEvent.click(submitButton);

            await waitFor(() => {
                expect(screen.queryByText("پسورد و تکرار رمز عبور باید یکسان باشد")).not.toBeInTheDocument();
            });
        });
    });
    describe("Form Submission", () => {
        it('Should enable the submit button when the inputs are valid', async () => {
            render(<MockAppWithProviders><ChangePasswordForm /></MockAppWithProviders>);

            const submitButton = screen.getByRole('button', { name: 'ثبت' });

            // Simulate entering valid values in the form fields
            const currentPasswordInput = screen.queryByLabelText('رمز عبور فعلی');
            const newPasswordInput = screen.queryByLabelText('رمز عبور جدید');
            const confirmPasswordInput = screen.queryByLabelText('تکرار رمز عبور جدید');

            fireEvent.change(currentPasswordInput, { target: { value: 'Witel@fani0' } });
            fireEvent.change(newPasswordInput, { target: { value: 'Witel@fani1' } });
            fireEvent.change(confirmPasswordInput, { target: { value: 'Witel@fani1' } });

            // Check if the submit button is enabled
            await waitFor(() => {
                expect(submitButton).not.toBeDisabled();
            });
        });
        it('Should request to api and resetform in success response', async () => {
            // Render the component
            render(<MockAppWithProviders><ChangePasswordForm /></MockAppWithProviders>);

            // Fill in the form fields
            const currentPasswordInput = screen.queryByLabelText('رمز عبور فعلی');
            const newPasswordInput = screen.queryByLabelText('رمز عبور جدید');
            const confirmPasswordInput = screen.queryByLabelText('تکرار رمز عبور جدید');

            fireEvent.change(currentPasswordInput, { target: { value: 'Witel@fani0' } });
            fireEvent.change(newPasswordInput, { target: { value: 'Witel@fani1' } });
            fireEvent.change(confirmPasswordInput, { target: { value: 'Witel@fani1' } });

            // Submit the form
            const submitButton = screen.getByRole('button', { name: 'ثبت' });
            await userEvent.click(submitButton);

            await waitFor(() => {
                expect(currentPasswordInput).toHaveValue('');
                expect(newPasswordInput).toHaveValue('');
                expect(confirmPasswordInput).toHaveValue('');
            });
        });
        it('Should request to api and not resetform in error response', async () => {
            // Render the component
            render(<MockAppWithProviders><ChangePasswordForm /></MockAppWithProviders>);
            server.use([rest.get(SET_USER_PASSWORD, (req, res, ctx) => {
                return res(ctx.status(422))
            })])

            // Fill in the form fields wrong
            const currentPasswordInput = screen.queryByLabelText('رمز عبور فعلی');
            const newPasswordInput = screen.queryByLabelText('رمز عبور جدید');
            const confirmPasswordInput = screen.queryByLabelText('تکرار رمز عبور جدید');

            fireEvent.change(currentPasswordInput, { target: { value: 'incorrect' } });
            fireEvent.change(newPasswordInput, { target: { value: 'Witel@fani1' } });
            fireEvent.change(confirmPasswordInput, { target: { value: 'Witel@fani1' } });

            // Submit the form
            const submitButton = screen.getByRole('button', { name: 'ثبت' });
            await userEvent.click(submitButton);

            await waitFor(() => {
                expect(currentPasswordInput.value).toBe('incorrect');
                expect(newPasswordInput.value).toBe('Witel@fani1');
                expect(confirmPasswordInput.value).toBe('Witel@fani1');
            });
        });
    });
})