// Comprehensive Unit Test Template - Auto-Generated
// This template generates complete unit tests for any component/service/utility

import { render, screen, fireEvent, waitFor, act } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { vi, describe, it, expect, beforeEach, afterEach, beforeAll, afterAll } from 'vitest';
import { {{COMPONENT_NAME}} } from './{{COMPONENT_PATH}}';
{{#each IMPORTS}}
import { {{this.name}} } from '{{this.path}}';
{{/each}}

// Mock external dependencies
{{#each MOCKED_DEPENDENCIES}}
vi.mock('{{this.path}}', () => ({
  {{this.name}}: vi.fn({{this.mockImplementation}})
}));
{{/each}}

// Test data factory
const TestDataFactory = {
  // Valid test data
  valid: {
    {{#each VALID_TEST_DATA}}
    {{this.name}}: {{this.value}},
    {{/each}}
  },
  
  // Invalid test data
  invalid: {
    {{#each INVALID_TEST_DATA}}
    {{this.name}}: {{this.value}}, // {{this.reason}}
    {{/each}}
  },
  
  // Edge case data
  edgeCases: {
    {{#each EDGE_CASE_DATA}}
    {{this.name}}: {{this.value}}, // {{this.description}}
    {{/each}}
  }
};

describe('{{COMPONENT_NAME}}', () => {
  let user: ReturnType<typeof userEvent.setup>;
  
  beforeAll(() => {
    // Global setup
    {{#each GLOBAL_SETUP}}
    {{this.code}}
    {{/each}}
  });

  beforeEach(() => {
    user = userEvent.setup();
    vi.clearAllMocks();
    {{#each BEFORE_EACH_SETUP}}
    {{this.code}}
    {{/each}}
  });

  afterEach(() => {
    vi.clearAllTimers();
    vi.restoreAllMocks();
    {{#each AFTER_EACH_CLEANUP}}
    {{this.code}}
    {{/each}}
  });

  afterAll(() => {
    {{#each GLOBAL_CLEANUP}}
    {{this.code}}
    {{/each}}
  });

  // === RENDERING TESTS ===
  describe('Rendering', () => {
    it('renders without crashing', () => {
      expect(() => render(<{{COMPONENT_NAME}} />)).not.toThrow();
    });

    it('renders with default props', () => {
      render(<{{COMPONENT_NAME}} />);
      expect(screen.getByTestId('{{DEFAULT_TEST_ID}}')).toBeInTheDocument();
    });

    {{#each REQUIRED_PROPS}}
    it('renders with required prop: {{this.name}}', () => {
      const props = { {{this.name}}: TestDataFactory.valid.{{this.name}} };
      render(<{{COMPONENT_NAME}} {...props} />);
      expect(screen.getByTestId('{{../DEFAULT_TEST_ID}}')).toBeInTheDocument();
    });
    {{/each}}

    it('renders with all props provided', () => {
      const allProps = {
        {{#each ALL_PROPS}}
        {{this.name}}: TestDataFactory.valid.{{this.name}},
        {{/each}}
      };
      render(<{{COMPONENT_NAME}} {...allProps} />);
      expect(screen.getByTestId('{{DEFAULT_TEST_ID}}')).toBeInTheDocument();
    });

    {{#if HAS_CONDITIONAL_RENDERING}}
    describe('Conditional Rendering', () => {
      {{#each CONDITIONAL_RENDERS}}
      it('{{this.description}}', () => {
        const props = {{this.props}};
        render(<{{../COMPONENT_NAME}} {...props} />);
        
        {{#if this.shouldRender}}
        expect(screen.getByTestId('{{this.testId}}')).toBeInTheDocument();
        {{else}}
        expect(screen.queryByTestId('{{this.testId}}')).not.toBeInTheDocument();
        {{/if}}
      });
      {{/each}}
    });
    {{/if}}

    {{#if HAS_LOADING_STATES}}
    describe('Loading States', () => {
      it('shows loading state', () => {
        render(<{{COMPONENT_NAME}} loading={true} />);
        expect(screen.getByTestId('loading-indicator')).toBeInTheDocument();
      });

      it('hides content during loading', () => {
        render(<{{COMPONENT_NAME}} loading={true} />);
        expect(screen.queryByTestId('{{CONTENT_TEST_ID}}')).not.toBeInTheDocument();
      });
    });
    {{/if}}

    {{#if HAS_ERROR_STATES}}
    describe('Error States', () => {
      it('displays error message when error prop is provided', () => {
        const errorMessage = 'Test error message';
        render(<{{COMPONENT_NAME}} error={errorMessage} />);
        expect(screen.getByText(errorMessage)).toBeInTheDocument();
      });

      it('displays error boundary fallback on render error', () => {
        const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
        
        // Force an error by providing invalid props
        render(<{{COMPONENT_NAME}} {{ERROR_TRIGGERING_PROPS}} />);
        
        expect(screen.getByText(/something went wrong/i)).toBeInTheDocument();
        consoleSpy.mockRestore();
      });
    });
    {{/if}}
  });

  // === INTERACTION TESTS ===
  describe('User Interactions', () => {
    {{#each USER_INTERACTIONS}}
    describe('{{this.name}} Interaction', () => {
      it('{{this.description}}', async () => {
        const mockHandler = vi.fn();
        const props = { {{this.handlerProp}}: mockHandler };
        
        render(<{{../COMPONENT_NAME}} {...props} />);
        
        const element = screen.getBy{{this.selector}}('{{this.identifier}}');
        {{#if this.isUserEvent}}
        await user.{{this.action}}(element);
        {{else}}
        fireEvent.{{this.action}}(element);
        {{/if}}
        
        {{#if this.hasAsyncBehavior}}
        await waitFor(() => {
          expect(mockHandler).toHaveBeenCalledTimes({{this.expectedCalls}});
        });
        {{else}}
        expect(mockHandler).toHaveBeenCalledTimes({{this.expectedCalls}});
        {{/if}}
        
        {{#if this.expectedArgs}}
        expect(mockHandler).toHaveBeenCalledWith({{this.expectedArgs}});
        {{/if}}
      });

      {{#if this.hasValidation}}
      it('validates {{this.name}} input', async () => {
        render(<{{../COMPONENT_NAME}} />);
        const element = screen.getBy{{this.selector}}('{{this.identifier}}');
        
        // Test invalid input
        await user.{{this.action}}(element);
        await user.type(element, '{{this.invalidValue}}');
        
        expect(screen.getByText('{{this.errorMessage}}')).toBeInTheDocument();
      });
      {{/if}}
    });
    {{/each}}

    describe('Keyboard Interactions', () => {
      it('handles Tab navigation correctly', async () => {
        render(<{{COMPONENT_NAME}} />);
        
        {{#each TAB_ORDER}}
        await user.tab();
        expect(screen.getByTestId('{{this.testId}}')).toHaveFocus();
        {{/each}}
      });

      {{#each KEYBOARD_SHORTCUTS}}
      it('handles {{this.keys}} keyboard shortcut', async () => {
        const mockHandler = vi.fn();
        render(<{{../COMPONENT_NAME}} {{this.handlerProp}}={mockHandler} />);
        
        await user.keyboard('{{this.keys}}');
        expect(mockHandler).toHaveBeenCalled();
      });
      {{/each}}
    });

    {{#if HAS_FORM_ELEMENTS}}
    describe('Form Interactions', () => {
      it('submits form with valid data', async () => {
        const mockSubmit = vi.fn();
        render(<{{COMPONENT_NAME}} onSubmit={mockSubmit} />);
        
        // Fill form fields
        {{#each FORM_FIELDS}}
        const {{this.name}}Field = screen.getByLabelText('{{this.label}}');
        await user.type({{this.name}}Field, TestDataFactory.valid.{{this.name}});
        {{/each}}
        
        // Submit form
        const submitButton = screen.getByRole('button', { name: /submit/i });
        await user.click(submitButton);
        
        expect(mockSubmit).toHaveBeenCalledWith({
          {{#each FORM_FIELDS}}
          {{this.name}}: TestDataFactory.valid.{{this.name}},
          {{/each}}
        });
      });

      it('prevents submission with invalid data', async () => {
        const mockSubmit = vi.fn();
        render(<{{COMPONENT_NAME}} onSubmit={mockSubmit} />);
        
        // Submit without filling required fields
        const submitButton = screen.getByRole('button', { name: /submit/i });
        await user.click(submitButton);
        
        expect(mockSubmit).not.toHaveBeenCalled();
        {{#each REQUIRED_FORM_FIELDS}}
        expect(screen.getByText('{{this.name}} is required')).toBeInTheDocument();
        {{/each}}
      });
    });
    {{/if}}
  });

  // === STATE MANAGEMENT TESTS ===
  {{#if HAS_INTERNAL_STATE}}
  describe('State Management', () => {
    {{#each STATE_VARIABLES}}
    describe('{{this.name}} State', () => {
      it('initializes with correct default value', () => {
        render(<{{../../COMPONENT_NAME}} />);
        expect(screen.getByTestId('{{this.testId}}')).toHaveTextContent('{{this.defaultValue}}');
      });

      it('updates when {{this.trigger}} occurs', async () => {
        render(<{{../../COMPONENT_NAME}} />);
        
        const trigger = screen.getByTestId('{{this.triggerTestId}}');
        await user.click(trigger);
        
        await waitFor(() => {
          expect(screen.getByTestId('{{this.testId}}')).toHaveTextContent('{{this.updatedValue}}');
        });
      });

      {{#if this.hasValidation}}
      it('validates {{this.name}} before updating', async () => {
        render(<{{../../COMPONENT_NAME}} />);
        
        const input = screen.getByTestId('{{this.inputTestId}}');
        await user.type(input, '{{this.invalidValue}}');
        
        expect(screen.getByTestId('{{this.testId}}')).toHaveTextContent('{{this.defaultValue}}');
        expect(screen.getByText('{{this.errorMessage}}')).toBeInTheDocument();
      });
      {{/if}}
    });
    {{/each}}

    it('resets all state correctly', async () => {
      render(<{{COMPONENT_NAME}} />);
      
      // Modify state
      {{#each STATE_VARIABLES}}
      const {{this.name}}Trigger = screen.getByTestId('{{this.triggerTestId}}');
      await user.click({{this.name}}Trigger);
      {{/each}}
      
      // Reset state
      const resetButton = screen.getByTestId('reset-button');
      await user.click(resetButton);
      
      // Verify all state is reset
      {{#each STATE_VARIABLES}}
      expect(screen.getByTestId('{{this.testId}}')).toHaveTextContent('{{this.defaultValue}}');
      {{/each}}
    });
  });
  {{/if}}

  // === PROPS VALIDATION TESTS ===
  describe('Props Validation', () => {
    {{#each ALL_PROPS}}
    describe('{{this.name}} Prop', () => {
      it('accepts valid {{this.type}} value', () => {
        const props = { {{this.name}}: TestDataFactory.valid.{{this.name}} };
        expect(() => render(<{{../COMPONENT_NAME}} {...props} />)).not.toThrow();
      });

      {{#if this.isRequired}}
      it('handles missing required prop gracefully', () => {
        const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
        render(<{{../COMPONENT_NAME}} />);
        expect(consoleSpy).toHaveBeenCalledWith(
          expect.stringContaining('{{this.name}}')
        );
        consoleSpy.mockRestore();
      });
      {{/if}}

      {{#if this.hasDefaultValue}}
      it('uses default value when prop not provided', () => {
        render(<{{../COMPONENT_NAME}} />);
        expect(screen.getByTestId('{{this.testId}}')).toHaveTextContent('{{this.defaultValue}}');
      });
      {{/if}}

      {{#each this.validations}}
      it('validates {{../name}}: {{this.description}}', () => {
        const props = { {{../name}}: {{this.testValue}} };
        {{#if this.shouldThrow}}
        expect(() => render(<{{../../COMPONENT_NAME}} {...props} />)).toThrow();
        {{else}}
        expect(() => render(<{{../../COMPONENT_NAME}} {...props} />)).not.toThrow();
        {{/if}}
      });
      {{/each}}
    });
    {{/each}}

    it('spreads additional props correctly', () => {
      const additionalProps = {
        'data-custom': 'custom-value',
        className: 'custom-class',
        id: 'custom-id'
      };
      
      render(<{{COMPONENT_NAME}} {...additionalProps} />);
      const element = screen.getByTestId('{{DEFAULT_TEST_ID}}');
      
      expect(element).toHaveAttribute('data-custom', 'custom-value');
      expect(element).toHaveClass('custom-class');
      expect(element).toHaveAttribute('id', 'custom-id');
    });
  });

  // === ASYNC BEHAVIOR TESTS ===
  {{#if HAS_ASYNC_BEHAVIOR}}
  describe('Async Behavior', () => {
    {{#each ASYNC_OPERATIONS}}
    describe('{{this.name}}', () => {
      it('handles successful {{this.name}}', async () => {
        const mockData = TestDataFactory.valid.{{this.responseData}};
        const mockApi = vi.fn().mockResolvedValue(mockData);
        {{this.mockSetup}}
        
        render(<{{../COMPONENT_NAME}} />);
        
        const trigger = screen.getByTestId('{{this.triggerTestId}}');
        await user.click(trigger);
        
        await waitFor(() => {
          expect(screen.getByTestId('{{this.successTestId}}')).toBeInTheDocument();
        });
        
        expect(mockApi).toHaveBeenCalledWith({{this.expectedArgs}});
      });

      it('handles {{this.name}} error', async () => {
        const errorMessage = 'API Error';
        const mockApi = vi.fn().mockRejectedValue(new Error(errorMessage));
        {{this.mockSetup}}
        
        render(<{{../COMPONENT_NAME}} />);
        
        const trigger = screen.getByTestId('{{this.triggerTestId}}');
        await user.click(trigger);
        
        await waitFor(() => {
          expect(screen.getByText(errorMessage)).toBeInTheDocument();
        });
      });

      it('shows loading state during {{this.name}}', async () => {
        let resolvePromise: (value: any) => void;
        const mockApi = vi.fn(() => new Promise(resolve => {
          resolvePromise = resolve;
        }));
        {{this.mockSetup}}
        
        render(<{{../COMPONENT_NAME}} />);
        
        const trigger = screen.getByTestId('{{this.triggerTestId}}');
        await user.click(trigger);
        
        expect(screen.getByTestId('loading-{{this.name}}')).toBeInTheDocument();
        
        act(() => {
          resolvePromise(TestDataFactory.valid.{{this.responseData}});
        });
        
        await waitFor(() => {
          expect(screen.queryByTestId('loading-{{this.name}}')).not.toBeInTheDocument();
        });
      });
    });
    {{/each}}
  });
  {{/if}}

  // === ACCESSIBILITY TESTS ===
  describe('Accessibility', () => {
    it('has proper ARIA attributes', () => {
      render(<{{COMPONENT_NAME}} />);
      const element = screen.getByTestId('{{DEFAULT_TEST_ID}}');
      
      {{#each ARIA_ATTRIBUTES}}
      expect(element).toHaveAttribute('{{this.name}}', '{{this.value}}');
      {{/each}}
    });

    it('supports screen readers', () => {
      render(<{{COMPONENT_NAME}} />);
      
      {{#each SCREEN_READER_ELEMENTS}}
      const element = screen.getBy{{this.selector}}('{{this.identifier}}');
      expect(element).toHaveAttribute('aria-label', '{{this.ariaLabel}}');
      {{/each}}
    });

    it('maintains focus management', async () => {
      render(<{{COMPONENT_NAME}} />);
      
      // Test focus trap if applicable
      {{#if HAS_FOCUS_TRAP}}
      const firstFocusable = screen.getByTestId('{{FIRST_FOCUSABLE_ELEMENT}}');
      const lastFocusable = screen.getByTestId('{{LAST_FOCUSABLE_ELEMENT}}');
      
      firstFocusable.focus();
      await user.tab({ shift: true });
      expect(lastFocusable).toHaveFocus();
      
      lastFocusable.focus();
      await user.tab();
      expect(firstFocusable).toHaveFocus();
      {{/if}}
    });

    {{#each KEYBOARD_NAVIGATION_TESTS}}
    it('{{this.description}}', async () => {
      render(<{{../COMPONENT_NAME}} />);
      
      {{#each this.steps}}
      await user.keyboard('{{this.key}}');
      expect(screen.getByTestId('{{this.expectedFocus}}')).toHaveFocus();
      {{/each}}
    });
    {{/each}}
  });

  // === PERFORMANCE TESTS ===
  describe('Performance', () => {
    it('does not cause unnecessary re-renders', () => {
      const renderSpy = vi.fn();
      const TestWrapper = React.memo((props: any) => {
        renderSpy();
        return <{{COMPONENT_NAME}} {...props} />;
      });
      
      const { rerender } = render(<TestWrapper />);
      expect(renderSpy).toHaveBeenCalledTimes(1);
      
      // Re-render with same props
      rerender(<TestWrapper />);
      expect(renderSpy).toHaveBeenCalledTimes(1);
      
      // Re-render with different props
      rerender(<TestWrapper newProp="value" />);
      expect(renderSpy).toHaveBeenCalledTimes(2);
    });

    {{#if HAS_MEMOIZATION}}
    it('memoizes expensive calculations', () => {
      const expensiveCalculation = vi.fn().mockReturnValue('calculated-value');
      
      render(<{{COMPONENT_NAME}} calculate={expensiveCalculation} input="test" />);
      expect(expensiveCalculation).toHaveBeenCalledTimes(1);
      
      // Re-render with same input
      render(<{{COMPONENT_NAME}} calculate={expensiveCalculation} input="test" />);
      expect(expensiveCalculation).toHaveBeenCalledTimes(1); // Should not recalculate
      
      // Re-render with different input
      render(<{{COMPONENT_NAME}} calculate={expensiveCalculation} input="new-test" />);
      expect(expensiveCalculation).toHaveBeenCalledTimes(2); // Should recalculate
    });
    {{/if}}
  });

  // === EDGE CASES AND ERROR HANDLING ===
  describe('Edge Cases', () => {
    {{#each EDGE_CASES}}
    it('handles {{this.description}}', {{#if this.isAsync}}async {{/if}}() => {
      {{#if this.setup}}
      {{this.setup}}
      {{/if}}
      
      const props = {{this.props}};
      
      {{#if this.shouldThrow}}
      expect(() => render(<{{../COMPONENT_NAME}} {...props} />)).toThrow('{{this.expectedError}}');
      {{else}}
      expect(() => render(<{{../COMPONENT_NAME}} {...props} />)).not.toThrow();
      {{/if}}
      
      {{#if this.additionalAssertions}}
      {{#each this.additionalAssertions}}
      {{this.assertion}}
      {{/each}}
      {{/if}}
    });
    {{/each}}

    it('handles component unmounting gracefully', () => {
      const { unmount } = render(<{{COMPONENT_NAME}} />);
      expect(() => unmount()).not.toThrow();
    });

    {{#if HAS_CLEANUP}}
    it('cleans up resources on unmount', () => {
      const mockCleanup = vi.fn();
      {{CLEANUP_SETUP}}
      
      const { unmount } = render(<{{COMPONENT_NAME}} />);
      unmount();
      
      expect(mockCleanup).toHaveBeenCalled();
    });
    {{/if}}
  });
});

// === UTILITY FUNCTION TESTS (if applicable) ===
{{#if HAS_UTILITY_FUNCTIONS}}
{{#each UTILITY_FUNCTIONS}}
describe('{{this.name}} utility', () => {
  {{#each this.testCases}}
  it('{{this.description}}', {{#if this.isAsync}}async {{/if}}() => {
    const input = {{this.input}};
    const expected = {{this.expected}};
    
    {{#if this.isAsync}}
    const result = await {{../name}}(input);
    {{else}}
    const result = {{../name}}(input);
    {{/if}}
    
    expect(result).toEqual(expected);
  });
  {{/each}}

  {{#each this.errorCases}}
  it('throws error: {{this.description}}', {{#if this.isAsync}}async {{/if}}() => {
    const input = {{this.input}};
    
    {{#if this.isAsync}}
    await expect({{../name}}(input)).rejects.toThrow('{{this.expectedError}}');
    {{else}}
    expect(() => {{../name}}(input)).toThrow('{{this.expectedError}}');
    {{/if}}
  });
  {{/each}}
});
{{/each}}
{{/if}}

// Export test utilities for reuse
export { TestDataFactory };