/**
 * Tests for FormTextarea Component
 * Verifies textarea field rendering, accessibility, and error handling
 */

import { render, screen } from '@testing-library/react';
import { FormTextarea } from '@/components/forms/FormTextarea';
import type { FieldError } from 'react-hook-form';

describe('FormTextarea', () => {
  describe('Basic Rendering', () => {
    it('renders with label and textarea', () => {
      render(<FormTextarea label="Description" name="description" />);

      expect(screen.getByLabelText('Description')).toBeInTheDocument();
      expect(screen.getByRole('textbox')).toBeInTheDocument();
    });

    it('renders with description', () => {
      render(
        <FormTextarea
          label="Personality Prompt"
          name="personality"
          description="Define the agent's personality and behavior"
        />
      );

      expect(screen.getByText("Define the agent's personality and behavior")).toBeInTheDocument();
    });

    it('renders description before textarea', () => {
      const { container } = render(
        <FormTextarea label="Description" name="description" description="Helper text" />
      );

      const description = container.querySelector('#description-description');
      const textarea = container.querySelector('textarea');

      // Get positions
      const descriptionRect = description?.getBoundingClientRect();
      const textareaRect = textarea?.getBoundingClientRect();

      // Description should appear (both should exist)
      expect(description).toBeInTheDocument();
      expect(textarea).toBeInTheDocument();

      // In the DOM order, description comes before textarea
      expect(descriptionRect).toBeDefined();
      expect(textareaRect).toBeDefined();
    });
  });

  describe('Required Field', () => {
    it('shows asterisk when required is true', () => {
      render(<FormTextarea label="Description" name="description" required />);

      expect(screen.getByText('*')).toBeInTheDocument();
    });

    it('does not show asterisk when required is false', () => {
      render(<FormTextarea label="Description" name="description" required={false} />);

      expect(screen.queryByText('*')).not.toBeInTheDocument();
    });
  });

  describe('Error Handling', () => {
    it('displays error message when error prop is provided', () => {
      const error: FieldError = {
        type: 'required',
        message: 'Description is required',
      };

      render(<FormTextarea label="Description" name="description" error={error} />);

      expect(screen.getByText('Description is required')).toBeInTheDocument();
    });

    it('sets aria-invalid when error exists', () => {
      const error: FieldError = {
        type: 'required',
        message: 'Description is required',
      };

      render(<FormTextarea label="Description" name="description" error={error} />);

      const textarea = screen.getByRole('textbox');
      expect(textarea).toHaveAttribute('aria-invalid', 'true');
    });

    it('sets aria-describedby with error ID when error exists', () => {
      const error: FieldError = {
        type: 'required',
        message: 'Description is required',
      };

      render(<FormTextarea label="Description" name="description" error={error} />);

      const textarea = screen.getByRole('textbox');
      expect(textarea).toHaveAttribute('aria-describedby', 'description-error');
    });

    it('renders error with role="alert"', () => {
      const error: FieldError = {
        type: 'required',
        message: 'Description is required',
      };

      render(<FormTextarea label="Description" name="description" error={error} />);

      const errorElement = screen.getByRole('alert');
      expect(errorElement).toHaveTextContent('Description is required');
    });
  });

  describe('Accessibility', () => {
    it('links label to textarea via htmlFor/id', () => {
      render(<FormTextarea label="Description" name="description" />);

      const label = screen.getByText('Description');
      const textarea = screen.getByRole('textbox');

      expect(label).toHaveAttribute('for', 'description');
      expect(textarea).toHaveAttribute('id', 'description');
    });

    it('sets aria-describedby with description ID when description exists', () => {
      render(
        <FormTextarea
          label="Description"
          name="description"
          description="Enter a detailed description"
        />
      );

      const textarea = screen.getByRole('textbox');
      expect(textarea).toHaveAttribute('aria-describedby', 'description-description');
    });

    it('combines error and description IDs in aria-describedby', () => {
      const error: FieldError = {
        type: 'required',
        message: 'Description is required',
      };

      render(
        <FormTextarea
          label="Description"
          name="description"
          description="Enter a detailed description"
          error={error}
        />
      );

      const textarea = screen.getByRole('textbox');
      expect(textarea).toHaveAttribute(
        'aria-describedby',
        'description-error description-description'
      );
    });
  });

  describe('Textarea Props Forwarding', () => {
    it('forwards textarea props correctly', () => {
      render(
        <FormTextarea
          label="Description"
          name="description"
          placeholder="Enter description"
          rows={5}
          disabled
        />
      );

      const textarea = screen.getByRole('textbox');
      expect(textarea).toHaveAttribute('placeholder', 'Enter description');
      expect(textarea).toHaveAttribute('rows', '5');
      expect(textarea).toBeDisabled();
    });

    it('accepts register() props via registration', () => {
      const registerProps = {
        name: 'description',
        onChange: jest.fn(),
        onBlur: jest.fn(),
        ref: jest.fn(),
      };

      render(<FormTextarea label="Description" registration={registerProps} />);

      const textarea = screen.getByRole('textbox');
      expect(textarea).toBeInTheDocument();
      expect(textarea).toHaveAttribute('id', 'description');
    });

    it('extracts name from spread props', () => {
      const spreadProps = {
        name: 'content',
        onChange: jest.fn(),
      };

      render(<FormTextarea label="Content" {...spreadProps} />);

      const textarea = screen.getByRole('textbox');
      expect(textarea).toHaveAttribute('id', 'content');
    });
  });

  describe('Error Cases', () => {
    it('throws error when name is not provided', () => {
      // Suppress console.error for this test
      const consoleError = jest.spyOn(console, 'error').mockImplementation(() => {});

      expect(() => {
        render(<FormTextarea label="Description" />);
      }).toThrow('FormTextarea: name must be provided either explicitly or via register()');

      consoleError.mockRestore();
    });
  });

  describe('Layout and Styling', () => {
    it('applies correct spacing classes', () => {
      const { container } = render(<FormTextarea label="Description" name="description" />);

      const wrapper = container.firstChild as HTMLElement;
      expect(wrapper).toHaveClass('space-y-2');
    });

    it('applies correct error styling', () => {
      const error: FieldError = {
        type: 'required',
        message: 'Description is required',
      };

      render(<FormTextarea label="Description" name="description" error={error} />);

      const errorElement = screen.getByRole('alert');
      expect(errorElement).toHaveClass('text-sm', 'text-destructive');
    });

    it('applies correct description styling', () => {
      const { container } = render(
        <FormTextarea label="Description" name="description" description="Helper text" />
      );

      const description = container.querySelector('#description-description');
      expect(description).toHaveClass('text-sm', 'text-muted-foreground');
    });
  });

  describe('Name Priority', () => {
    it('uses explicit name over registration name', () => {
      const registerProps = {
        name: 'fromRegister',
        onChange: jest.fn(),
        onBlur: jest.fn(),
        ref: jest.fn(),
      };

      render(<FormTextarea label="Content" name="explicit" registration={registerProps} />);

      const textarea = screen.getByRole('textbox');
      expect(textarea).toHaveAttribute('id', 'explicit');
    });

    it('uses registration name when explicit name not provided', () => {
      const registerProps = {
        name: 'fromRegister',
        onChange: jest.fn(),
        onBlur: jest.fn(),
        ref: jest.fn(),
      };

      render(<FormTextarea label="Content" registration={registerProps} />);

      const textarea = screen.getByRole('textbox');
      expect(textarea).toHaveAttribute('id', 'fromRegister');
    });
  });
});
