import { render } from '@testing-library/react';
import { notFound } from 'next/navigation';
import { getProfile } from '@/actions/getProfile';
import { getSettings } from '@/actions/getSettings';
import { ProfileForm } from './ProfileForm';
import SettingsPage from './page';
import type { Mock } from 'vitest';

vi.mock('next/navigation', () => ({
    notFound: vi.fn(),
}));

vi.mock('@/actions/getProfile', () => ({
    getProfile: vi.fn().mockReturnValue({}),
}));

vi.mock('@/actions/getSettings', () => ({
    getSettings: vi.fn().mockReturnValue({}),
}));

vi.mock('./ProfileForm', () => ({
    ProfileForm: vi.fn(() => <div>ProfileForm</div>),
}));

describe('<SettingsPage>', () => {
    afterEach(() => {
        vi.clearAllMocks();
    });

    describe('when search params has "IPCountry"', () => {
        it('should call "getSettings" with correct params', async () => {
            render(
                await SettingsPage({
                    params: Promise.resolve({ locale: 'en', token: 'token' }),
                    searchParams: Promise.resolve({ IPCountry: 'EE' }),
                })
            );

            expect(getSettings).toHaveBeenCalledWith({
                IPCountry: 'EE',
            });
        });
    });

    describe('when resolved with "data"', () => {
        it('should render "ProfileForm" with correct props', async () => {
            const getProfileResolvedValue = {
                data: { email: 'test@email.com' },
            };
            const getSettingsResolvedValue = {
                data: { isDateOfBirthAllowed: true },
            };
            (getProfile as Mock).mockResolvedValue(getProfileResolvedValue);
            (getSettings as Mock).mockResolvedValue(getSettingsResolvedValue);

            const props = {
                params: Promise.resolve({ locale: 'en', token: 'token' }),
                searchParams: Promise.resolve({ IPCountry: 'EE' }),
            };

            render(await SettingsPage(props));

            expect(ProfileForm).toHaveBeenCalledWith(
                {
                    defaultValues: getProfileResolvedValue.data,
                    isDateOfBirthAllowed:
                        getSettingsResolvedValue.data.isDateOfBirthAllowed,
                },
                undefined
            );
        });
    });

    describe('when "getProfile" returns an error', () => {
        describe('when error type is "PAGE_NOT_FOUND"', () => {
            it('should call "notFound" page', async () => {
                (getProfile as Mock).mockResolvedValue({
                    error: { type: 'PAGE_NOT_FOUND' },
                });
                (getSettings as Mock).mockResolvedValue({ data: {} });

                const props = {
                    params: Promise.resolve({ locale: 'en', token: 'token' }),
                    searchParams: Promise.resolve({ IPCountry: 'EE' }),
                };

                render(await SettingsPage(props));

                expect(notFound).toBeCalled();
            });
        });

        describe('when error type is any other', () => {
            it('should throw that error', async () => {
                const error = { type: 'BAD_REQUEST', message: 'Bad request' };

                (getProfile as Mock).mockResolvedValue({ error });
                (getSettings as Mock).mockResolvedValue({ data: {} });

                const props = {
                    params: Promise.resolve({ locale: 'en', token: 'token' }),
                    searchParams: Promise.resolve({ IPCountry: 'EE' }),
                };

                expect(await SettingsPage(props).catch(err => err)).toBe(
                    error.message
                );
            });
        });
    });

    describe('when "getSettings" returns an error', () => {
        describe('when error type is any other', () => {
            it('should throw that error', async () => {
                const error = { type: 'BAD_REQUEST', message: 'Bad request' };

                (getProfile as Mock).mockResolvedValue({ data: {} });
                (getSettings as Mock).mockResolvedValue({ error });

                const props = {
                    params: Promise.resolve({ locale: 'en', token: 'token' }),
                    searchParams: Promise.resolve({ IPCountry: 'EE' }),
                };

                expect(await SettingsPage(props).catch(err => err)).toBe(
                    error.message
                );
            });
        });
    });
});
