import { describe, it, expect, vi } from 'vitest';
import { render, screen, fireEvent } from '@testing-library/react';
import FormCurrencyInput from '../FormCurrencyInput';

describe('FormCurrencyInput', () => {
  const defaultProps = {
    value: 0,
    onChange: vi.fn(),
  };

  beforeEach(() => {
    vi.clearAllMocks();
  });

  describe('Label Rendering', () => {
    it('renders without label when not provided', () => {
      render(<FormCurrencyInput {...defaultProps} />);
      expect(screen.queryByRole('label')).not.toBeInTheDocument();
    });

    it('renders label when provided', () => {
      render(<FormCurrencyInput {...defaultProps} label="Price" />);
      expect(screen.getByText('Price')).toBeInTheDocument();
    });

    it('shows required indicator when required', () => {
      render(<FormCurrencyInput {...defaultProps} label="Price" required />);
      expect(screen.getByText('*')).toBeInTheDocument();
    });

    it('does not show required indicator when not required', () => {
      render(<FormCurrencyInput {...defaultProps} label="Price" />);
      expect(screen.queryByText('*')).not.toBeInTheDocument();
    });
  });

  describe('Error Handling', () => {
    it('does not show error when not provided', () => {
      render(<FormCurrencyInput {...defaultProps} />);
      expect(screen.queryByText(/error/i)).not.toBeInTheDocument();
    });

    it('shows error message when provided', () => {
      render(<FormCurrencyInput {...defaultProps} error="Price is required" />);
      expect(screen.getByText('Price is required')).toBeInTheDocument();
    });

    it('applies error styling to input', () => {
      render(<FormCurrencyInput {...defaultProps} error="Error" />);
      const input = screen.getByRole('textbox');
      expect(input).toHaveClass('border-red-500');
    });

    it('error has correct text color', () => {
      render(<FormCurrencyInput {...defaultProps} error="Price is required" />);
      const error = screen.getByText('Price is required');
      expect(error).toHaveClass('text-red-600');
    });
  });

  describe('Hint Rendering', () => {
    it('does not show hint when not provided', () => {
      render(<FormCurrencyInput {...defaultProps} />);
      expect(screen.queryByText(/hint/i)).not.toBeInTheDocument();
    });

    it('shows hint when provided', () => {
      render(<FormCurrencyInput {...defaultProps} hint="Enter price in dollars" />);
      expect(screen.getByText('Enter price in dollars')).toBeInTheDocument();
    });

    it('hides hint when error is shown', () => {
      render(
        <FormCurrencyInput
          {...defaultProps}
          hint="Enter price"
          error="Price required"
        />
      );
      expect(screen.queryByText('Enter price')).not.toBeInTheDocument();
      expect(screen.getByText('Price required')).toBeInTheDocument();
    });

    it('hint has correct text color', () => {
      render(<FormCurrencyInput {...defaultProps} hint="Helpful text" />);
      const hint = screen.getByText('Helpful text');
      expect(hint).toHaveClass('text-gray-500');
    });
  });

  describe('Input Behavior', () => {
    it('renders input with default placeholder', () => {
      render(<FormCurrencyInput {...defaultProps} />);
      const input = screen.getByPlaceholderText('$0.00');
      expect(input).toBeInTheDocument();
    });

    it('renders input with custom placeholder', () => {
      render(<FormCurrencyInput {...defaultProps} placeholder="Enter amount" />);
      const input = screen.getByPlaceholderText('Enter amount');
      expect(input).toBeInTheDocument();
    });

    it('displays formatted value', () => {
      render(<FormCurrencyInput {...defaultProps} value={1000} />);
      const input = screen.getByRole('textbox');
      expect(input).toHaveValue('$10.00');
    });

    it('calls onChange when value changes', () => {
      const onChange = vi.fn();
      render(<FormCurrencyInput {...defaultProps} onChange={onChange} />);
      const input = screen.getByRole('textbox');

      fireEvent.change(input, { target: { value: '500' } });
      expect(onChange).toHaveBeenCalledWith(500);
    });

    it('can be disabled', () => {
      render(<FormCurrencyInput {...defaultProps} disabled />);
      const input = screen.getByRole('textbox');
      expect(input).toBeDisabled();
    });

    it('applies disabled styling', () => {
      render(<FormCurrencyInput {...defaultProps} disabled />);
      const input = screen.getByRole('textbox');
      expect(input).toHaveClass('cursor-not-allowed');
    });
  });

  describe('Min/Max Props', () => {
    it('passes min prop to CurrencyInput', () => {
      const onChange = vi.fn();
      render(<FormCurrencyInput {...defaultProps} onChange={onChange} min={100} value={50} />);
      const input = screen.getByRole('textbox');

      fireEvent.blur(input);
      expect(onChange).toHaveBeenCalledWith(100);
    });

    it('passes max prop to CurrencyInput', () => {
      const onChange = vi.fn();
      render(<FormCurrencyInput {...defaultProps} onChange={onChange} max={1000} />);
      const input = screen.getByRole('textbox');

      fireEvent.change(input, { target: { value: '5000' } });
      expect(onChange).toHaveBeenCalledWith(1000);
    });
  });

  describe('Styling', () => {
    it('applies containerClassName to wrapper', () => {
      const { container } = render(
        <FormCurrencyInput {...defaultProps} containerClassName="my-container" />
      );
      expect(container.firstChild).toHaveClass('my-container');
    });

    it('applies className to input', () => {
      render(<FormCurrencyInput {...defaultProps} className="my-input" />);
      const input = screen.getByRole('textbox');
      expect(input).toHaveClass('my-input');
    });

    it('applies base input classes', () => {
      render(<FormCurrencyInput {...defaultProps} />);
      const input = screen.getByRole('textbox');
      expect(input).toHaveClass('w-full', 'px-3', 'py-2', 'border', 'rounded-lg');
    });

    it('applies normal border when no error', () => {
      render(<FormCurrencyInput {...defaultProps} />);
      const input = screen.getByRole('textbox');
      expect(input).toHaveClass('border-gray-300');
    });

    it('applies error border when error provided', () => {
      render(<FormCurrencyInput {...defaultProps} error="Error" />);
      const input = screen.getByRole('textbox');
      expect(input).toHaveClass('border-red-500');
      expect(input).not.toHaveClass('border-gray-300');
    });
  });

  describe('Accessibility', () => {
    it('associates label with input', () => {
      render(<FormCurrencyInput {...defaultProps} label="Price" />);
      const label = screen.getByText('Price');
      expect(label.tagName).toBe('LABEL');
    });

    it('marks input as required when required prop is true', () => {
      render(<FormCurrencyInput {...defaultProps} required />);
      const input = screen.getByRole('textbox');
      expect(input).toBeRequired();
    });
  });

  describe('Integration', () => {
    it('full form flow works correctly', () => {
      const onChange = vi.fn();
      render(
        <FormCurrencyInput
          label="Service Price"
          hint="Enter the price for this service"
          value={0}
          onChange={onChange}
          required
          min={100}
          max={100000}
        />
      );

      // Check label and hint render
      expect(screen.getByText('Service Price')).toBeInTheDocument();
      expect(screen.getByText('Enter the price for this service')).toBeInTheDocument();
      expect(screen.getByText('*')).toBeInTheDocument();

      // Enter a value
      const input = screen.getByRole('textbox');
      fireEvent.change(input, { target: { value: '2500' } });
      expect(onChange).toHaveBeenCalledWith(2500);
    });

    it('shows error state correctly', () => {
      render(
        <FormCurrencyInput
          label="Price"
          error="Price must be greater than $1.00"
          value={50}
          onChange={vi.fn()}
        />
      );

      expect(screen.getByText('Price must be greater than $1.00')).toBeInTheDocument();
      const input = screen.getByRole('textbox');
      expect(input).toHaveClass('border-red-500');
    });
  });
});
