import { act } from 'react';
import { describe, expect, it } from 'vitest';
import { useValidatedFields } from '../../src/hooks/useValidatedFields';
import { renderHook } from '../helpers/renderHook';

type FormValues = {
    password: string;
    confirmPassword: string;
};

function validate(values: FormValues) {
    return {
        password: values.password.length < 3 ? 'Password too short' : undefined,
        confirmPassword:
            values.confirmPassword !== values.password ? 'Passwords do not match' : undefined,
    };
}

describe('useValidatedFields', () => {
    it('initializes values and keeps errors hidden until fields are touched', () => {
        const { result } = renderHook(() =>
            useValidatedFields({
                initialValues: { password: '', confirmPassword: '' },
                validate,
            }),
        );

        expect(result.current.values).toEqual({ password: '', confirmPassword: '' });
        expect(result.current.errors).toEqual({});
        expect(result.current.isValid).toBe(false);
    });

    it('setFieldValue touches and validates by default', () => {
        const { result } = renderHook(() =>
            useValidatedFields({
                initialValues: { password: '', confirmPassword: '' },
                validate,
            }),
        );

        act(() => {
            result.current.setFieldValue('password', 'ab');
        });

        expect(result.current.values.password).toBe('ab');
        expect(result.current.errors.password).toBe('Password too short');
    });

    it('setFieldValue can skip touch and validation', () => {
        const { result } = renderHook(() =>
            useValidatedFields({
                initialValues: { password: '', confirmPassword: '' },
                validate,
            }),
        );

        act(() => {
            result.current.setFieldValue('password', 'ab', { touch: false, validate: false });
        });

        expect(result.current.values.password).toBe('ab');
        expect(result.current.errors).toEqual({});
    });

    it('validateAll can avoid touching fields when requested', () => {
        const { result } = renderHook(() =>
            useValidatedFields({
                initialValues: { password: 'abcd', confirmPassword: 'abce' },
                validate,
            }),
        );

        let validationErrors: ReturnType<typeof validate> | undefined;
        act(() => {
            validationErrors = result.current.validateAll({ touchAll: false });
        });

        expect(validationErrors).toEqual({
            password: undefined,
            confirmPassword: 'Passwords do not match',
        });
        expect(result.current.errors).toEqual({});
    });

    it('validateAll touches all fields by default', () => {
        const { result } = renderHook(() =>
            useValidatedFields({
                initialValues: { password: '', confirmPassword: '' },
                validate,
            }),
        );

        act(() => {
            result.current.validateAll();
        });

        expect(result.current.errors.password).toBe('Password too short');
        expect(result.current.errors.confirmPassword).toBeUndefined();
    });

    it('supports setFieldError, setErrors and clearErrors', () => {
        const { result } = renderHook(() =>
            useValidatedFields({
                initialValues: { password: 'abcd', confirmPassword: 'abcd' },
                validate,
            }),
        );

        act(() => {
            result.current.setFieldError('password', 'Server-side password issue');
        });
        expect(result.current.errors.password).toBe('Server-side password issue');

        act(() => {
            result.current.setErrors({
                password: undefined,
                confirmPassword: 'Still invalid',
            });
        });
        expect(result.current.errors.confirmPassword).toBe('Still invalid');

        act(() => {
            result.current.clearErrors();
        });
        expect(result.current.errors).toEqual({});
    });

    it('setValues with clearErrors resets touched state and revalidates', () => {
        const { result } = renderHook(() =>
            useValidatedFields({
                initialValues: { password: '', confirmPassword: '' },
                validate,
            }),
        );

        act(() => {
            result.current.setFieldValue('password', 'ab');
        });
        expect(result.current.errors.password).toBe('Password too short');

        act(() => {
            result.current.setValues(
                {
                    password: 'abcd',
                    confirmPassword: 'abcd',
                },
                { clearErrors: true },
            );
        });

        expect(result.current.values).toEqual({
            password: 'abcd',
            confirmPassword: 'abcd',
        });
        expect(result.current.errors).toEqual({});
        expect(result.current.isValid).toBe(true);
    });
});
