/**
 * NumberField Tests
 *
 * Tests the number field component including:
 * - Basic rendering
 * - Value parsing (string to number)
 * - Variable syntax handling
 * - Allowed variable types
 * - Error display
 */
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { render, screen, fireEvent } from '@testing-library/react';
import { NumberField } from './NumberField';
import { ActionField } from '../../types/action';
import { AvailableContext } from '../../types/workflow-context';

// Mock VariableInput
vi.mock('../VariableInput', () => ({
  VariableInput: ({
    value,
    onChange,
    placeholder,
    allowedTypes,
  }: {
    value: string;
    onChange: (v: string) => void;
    placeholder?: string;
    allowedTypes?: string[];
  }) => (
    <input
      data-testid="variable-input"
      value={value}
      onChange={(e) => onChange(e.target.value)}
      placeholder={placeholder}
      data-allowed-types={allowedTypes?.join(',')}
    />
  ),
}));

describe('NumberField', () => {
  const mockOnChange = vi.fn();

  const defaultField: ActionField = {
    label: 'Quantity',
    type: 'number',
    description: 'Enter a quantity',
    required: false,
  };

  const emptyContext: AvailableContext = {
    groups: [],
  };

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

  // ==========================================================================
  // Basic Rendering Tests
  // ==========================================================================

  describe('basic rendering', () => {
    it('renders the field label', () => {
      render(
        <NumberField
          fieldName="quantity"
          field={defaultField}
          value={0}
          onChange={mockOnChange}
          availableContext={emptyContext}
        />,
      );

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

    it('renders VariableInput component', () => {
      render(
        <NumberField
          fieldName="quantity"
          field={defaultField}
          value={0}
          onChange={mockOnChange}
          availableContext={emptyContext}
        />,
      );

      expect(screen.getByTestId('variable-input')).toBeInTheDocument();
    });

    it('converts numeric value to string for display', () => {
      render(
        <NumberField
          fieldName="quantity"
          field={defaultField}
          value={42}
          onChange={mockOnChange}
          availableContext={emptyContext}
        />,
      );

      expect(screen.getByTestId('variable-input')).toHaveValue('42');
    });

    it('handles empty/undefined value', () => {
      render(
        <NumberField
          fieldName="quantity"
          field={defaultField}
          value=""
          onChange={mockOnChange}
          availableContext={emptyContext}
        />,
      );

      expect(screen.getByTestId('variable-input')).toHaveValue('');
    });
  });

  // ==========================================================================
  // Required Indicator Tests
  // ==========================================================================

  describe('required indicator', () => {
    it('shows required asterisk when field is required', () => {
      const requiredField = { ...defaultField, required: true };

      render(
        <NumberField
          fieldName="quantity"
          field={requiredField}
          value={0}
          onChange={mockOnChange}
          availableContext={emptyContext}
        />,
      );

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

  // ==========================================================================
  // Value Parsing Tests
  // ==========================================================================

  describe('value parsing', () => {
    it('parses valid number strings to numbers', () => {
      render(
        <NumberField
          fieldName="quantity"
          field={defaultField}
          value=""
          onChange={mockOnChange}
          availableContext={emptyContext}
        />,
      );

      fireEvent.change(screen.getByTestId('variable-input'), {
        target: { value: '123' },
      });

      expect(mockOnChange).toHaveBeenCalledWith(123);
    });

    it('parses decimal numbers', () => {
      render(
        <NumberField
          fieldName="quantity"
          field={defaultField}
          value=""
          onChange={mockOnChange}
          availableContext={emptyContext}
        />,
      );

      fireEvent.change(screen.getByTestId('variable-input'), {
        target: { value: '12.5' },
      });

      expect(mockOnChange).toHaveBeenCalledWith(12.5);
    });

    it('keeps empty string as empty string', () => {
      render(
        <NumberField
          fieldName="quantity"
          field={defaultField}
          value={5}
          onChange={mockOnChange}
          availableContext={emptyContext}
        />,
      );

      fireEvent.change(screen.getByTestId('variable-input'), {
        target: { value: '' },
      });

      expect(mockOnChange).toHaveBeenCalledWith('');
    });

    it('keeps non-numeric strings as strings', () => {
      render(
        <NumberField
          fieldName="quantity"
          field={defaultField}
          value=""
          onChange={mockOnChange}
          availableContext={emptyContext}
        />,
      );

      fireEvent.change(screen.getByTestId('variable-input'), {
        target: { value: 'abc' },
      });

      expect(mockOnChange).toHaveBeenCalledWith('abc');
    });
  });

  // ==========================================================================
  // Variable Syntax Tests
  // ==========================================================================

  describe('variable syntax', () => {
    it('keeps variable syntax as string', () => {
      render(
        <NumberField
          fieldName="quantity"
          field={defaultField}
          value=""
          onChange={mockOnChange}
          availableContext={emptyContext}
        />,
      );

      fireEvent.change(screen.getByTestId('variable-input'), {
        target: { value: '{{Trigger.count}}' },
      });

      expect(mockOnChange).toHaveBeenCalledWith('{{Trigger.count}}');
    });

    it('displays variable syntax correctly', () => {
      render(
        <NumberField
          fieldName="quantity"
          field={defaultField}
          value="{{Trigger.count}}"
          onChange={mockOnChange}
          availableContext={emptyContext}
        />,
      );

      expect(screen.getByTestId('variable-input')).toHaveValue('{{Trigger.count}}');
    });
  });

  // ==========================================================================
  // Allowed Types Tests
  // ==========================================================================

  describe('allowed variable types', () => {
    it('defaults to integer allowed type', () => {
      render(
        <NumberField
          fieldName="quantity"
          field={defaultField}
          value={0}
          onChange={mockOnChange}
          availableContext={emptyContext}
        />,
      );

      expect(screen.getByTestId('variable-input')).toHaveAttribute('data-allowed-types', 'integer');
    });

    it('uses custom allowed_variable_types from field', () => {
      const fieldWithCustomTypes = {
        ...defaultField,
        allowed_variable_types: ['integer', 'string'] as ('integer' | 'string')[],
      };

      render(
        <NumberField
          fieldName="quantity"
          field={fieldWithCustomTypes}
          value={0}
          onChange={mockOnChange}
          availableContext={emptyContext}
        />,
      );

      expect(screen.getByTestId('variable-input')).toHaveAttribute(
        'data-allowed-types',
        'integer,string',
      );
    });
  });

  // ==========================================================================
  // Description Tests
  // ==========================================================================

  describe('description', () => {
    it('displays description when provided', () => {
      render(
        <NumberField
          fieldName="quantity"
          field={defaultField}
          value={0}
          onChange={mockOnChange}
          availableContext={emptyContext}
        />,
      );

      expect(screen.getByText('Enter a quantity')).toBeInTheDocument();
    });

    it('does not render description when not provided', () => {
      const fieldWithoutDescription = { ...defaultField, description: '' };

      const { container } = render(
        <NumberField
          fieldName="quantity"
          field={fieldWithoutDescription}
          value={0}
          onChange={mockOnChange}
          availableContext={emptyContext}
        />,
      );

      const descriptionElement = container.querySelector('.text-slate-500');
      expect(descriptionElement).not.toBeInTheDocument();
    });
  });

  // ==========================================================================
  // Error Display Tests
  // ==========================================================================

  describe('error display', () => {
    it('displays error message when provided', () => {
      render(
        <NumberField
          fieldName="quantity"
          field={defaultField}
          value={0}
          onChange={mockOnChange}
          availableContext={emptyContext}
          error="Must be a positive number"
        />,
      );

      expect(screen.getByText('Must be a positive number')).toBeInTheDocument();
    });
  });
});
