/**
 * Tests for useValidationErrorHandler hook
 */

import { renderHook } from '@testing-library/react';
import { toast } from 'sonner';
import { useValidationErrorHandler } from '@/lib/forms/hooks/useValidationErrorHandler';
import type { FieldErrors } from 'react-hook-form';

// Mock sonner toast
jest.mock('sonner', () => ({
  toast: {
    error: jest.fn(),
  },
}));

// Mock console.error to track debug logging
const originalConsoleError = console.error;
let consoleErrorMock: jest.SpyInstance;

beforeEach(() => {
  jest.clearAllMocks();
  consoleErrorMock = jest.spyOn(console, 'error').mockImplementation(() => {});
});

afterEach(() => {
  consoleErrorMock.mockRestore();
  console.error = originalConsoleError;
});

describe('useValidationErrorHandler', () => {
  describe('basic functionality', () => {
    it('shows toast with first error message', () => {
      const { result } = renderHook(() => useValidationErrorHandler({ debug: false }));

      const errors: FieldErrors = {
        name: { message: 'Name is required', type: 'required' },
      };

      result.current.onValidationError(errors);

      expect(toast.error).toHaveBeenCalledWith('Please fix form errors', {
        description: 'name: Name is required',
      });
    });

    it('uses custom toast title when provided', () => {
      const { result } = renderHook(() =>
        useValidationErrorHandler({
          toastTitle: 'Validation Failed',
          debug: false,
        })
      );

      const errors: FieldErrors = {
        email: { message: 'Invalid email', type: 'pattern' },
      };

      result.current.onValidationError(errors);

      expect(toast.error).toHaveBeenCalledWith('Validation Failed', {
        description: 'email: Invalid email',
      });
    });

    it('does nothing when no errors', () => {
      const { result } = renderHook(() => useValidationErrorHandler({ debug: false }));

      result.current.onValidationError({});

      expect(toast.error).not.toHaveBeenCalled();
    });
  });

  describe('nested errors', () => {
    it('handles nested field errors', () => {
      const { result } = renderHook(() => useValidationErrorHandler({ debug: false }));

      const errors: FieldErrors = {
        model_params: {
          temperature: { message: 'Temperature must be between 0 and 2', type: 'max' },
        },
      };

      result.current.onValidationError(errors);

      expect(toast.error).toHaveBeenCalledWith('Please fix form errors', {
        description: 'model_params.temperature: Temperature must be between 0 and 2',
      });
    });
  });

  describe('tab navigation', () => {
    it('navigates to correct tab when mapping provided', () => {
      const setActiveTab = jest.fn();
      const tabMapping = {
        name: 'basic',
        model_params: 'model',
      };

      const { result } = renderHook(() =>
        useValidationErrorHandler({
          tabMapping,
          setActiveTab,
          debug: false,
        })
      );

      const errors: FieldErrors = {
        model_params: {
          temperature: { message: 'Invalid', type: 'type' },
        },
      };

      result.current.onValidationError(errors);

      expect(setActiveTab).toHaveBeenCalledWith('model');
    });

    it('does not navigate if field not in mapping', () => {
      const setActiveTab = jest.fn();
      const tabMapping = {
        name: 'basic',
      };

      const { result } = renderHook(() =>
        useValidationErrorHandler({
          tabMapping,
          setActiveTab,
          debug: false,
        })
      );

      const errors: FieldErrors = {
        unknown_field: { message: 'Error', type: 'validation' },
      };

      result.current.onValidationError(errors);

      expect(setActiveTab).not.toHaveBeenCalled();
    });

    it('does not crash when setActiveTab not provided', () => {
      const tabMapping = { name: 'basic' };

      const { result } = renderHook(() =>
        useValidationErrorHandler({
          tabMapping,
          // setActiveTab not provided
          debug: false,
        })
      );

      const errors: FieldErrors = {
        name: { message: 'Required', type: 'required' },
      };

      expect(() => result.current.onValidationError(errors)).not.toThrow();
    });
  });

  describe('debug logging', () => {
    it('logs errors when debug is true', () => {
      const { result } = renderHook(() => useValidationErrorHandler({ debug: true }));

      const errors: FieldErrors = {
        name: { message: 'Required', type: 'required' },
      };

      result.current.onValidationError(errors);

      expect(consoleErrorMock).toHaveBeenCalledWith('[Form Validation] Errors:', errors);
    });

    it('does not log errors when debug is false', () => {
      const { result } = renderHook(() => useValidationErrorHandler({ debug: false }));

      const errors: FieldErrors = {
        name: { message: 'Required', type: 'required' },
      };

      result.current.onValidationError(errors);

      expect(consoleErrorMock).not.toHaveBeenCalled();
    });
  });

  describe('memoization', () => {
    it('returns stable callback reference', () => {
      const { result, rerender } = renderHook(() => useValidationErrorHandler({ debug: false }));

      const firstCallback = result.current.onValidationError;
      rerender();
      const secondCallback = result.current.onValidationError;

      expect(firstCallback).toBe(secondCallback);
    });

    it('returns new callback when options change', () => {
      const { result, rerender } = renderHook(
        ({ title }) => useValidationErrorHandler({ toastTitle: title, debug: false }),
        { initialProps: { title: 'Error A' } }
      );

      const firstCallback = result.current.onValidationError;
      rerender({ title: 'Error B' });
      const secondCallback = result.current.onValidationError;

      expect(firstCallback).not.toBe(secondCallback);
    });
  });
});
