import { jest } from '@jest/globals';
import React from 'react';
import { render, screen, fireEvent, within } from '@testing-library/react';
import SelectInput from '../pages/GlobalConfig/Inputs/SelectInput.js';

describe('SelectInput Component', () => {
  const mockOnChange = jest.fn();
  
  const defaultField = {
    Id: 'test-select-1',
    Label: 'Test Select',
    ProValue: '',
    Options: '["Option A", "Option B", "Option C"]',
  };

  beforeEach(() => {
    mockOnChange.mockClear();
  });

  it('renders the select component', () => {
    const { container } = render(<SelectInput field={defaultField} onChange={mockOnChange} />);
    const select = container.querySelector('.MuiSelect-select');
    expect(select).toBeInTheDocument();
  });

  it('renders disabled when disabled prop is true', () => {
    const { container } = render(<SelectInput field={defaultField} onChange={mockOnChange} disabled={true} />);
    const select = container.querySelector('.MuiInputBase-root');
    expect(select).toHaveClass('Mui-disabled');
  });

  it('displays helper text when provided', () => {
    render(
      <SelectInput field={defaultField} onChange={mockOnChange} helperText="Please select an option" />
    );
    expect(screen.getByText('Please select an option')).toBeInTheDocument();
  });

  it('handles invalid JSON Options gracefully and sets options to empty array', () => {
    const consoleSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
    const invalidField = { ...defaultField, Options: '[invalid json' };
    const { container } = render(<SelectInput field={invalidField} onChange={mockOnChange} />);
    const formControl = container.querySelector('.MuiFormControl-root');
    expect(formControl).toBeInTheDocument();
    // Verify the warning was logged
    expect(consoleSpy).toHaveBeenCalledWith('Invalid JSON for field: Test Select');
    consoleSpy.mockRestore();
  });

  it('handles empty Options', () => {
    const emptyOptionsField = { ...defaultField, Options: '' };
    const { container } = render(<SelectInput field={emptyOptionsField} onChange={mockOnChange} />);
    const formControl = container.querySelector('.MuiFormControl-root');
    expect(formControl).toBeInTheDocument();
  });

  it('handles undefined Options', () => {
    const noOptionsField = { ...defaultField, Options: undefined };
    const { container } = render(<SelectInput field={noOptionsField} onChange={mockOnChange} />);
    const formControl = container.querySelector('.MuiFormControl-root');
    expect(formControl).toBeInTheDocument();
  });

  it('handles object-style options with label and value', () => {
    const objectOptionsField = {
      ...defaultField,
      Options: '[{"label": "Label A", "value": "A"}, {"label": "Label B", "value": "B"}]',
    };
    const { container } = render(<SelectInput field={objectOptionsField} onChange={mockOnChange} />);
    const formControl = container.querySelector('.MuiFormControl-root');
    expect(formControl).toBeInTheDocument();
  });

  it('displays error state when error prop is true', () => {
    const { container } = render(
      <SelectInput field={defaultField} onChange={mockOnChange} error={true} />
    );
    const inputBase = container.querySelector('.MuiOutlinedInput-root');
    expect(inputBase).toHaveClass('Mui-error');
  });

  it('renders with pre-selected value', () => {
    const fieldWithValue = { ...defaultField, ProValue: 'Option B' };
    const { container } = render(<SelectInput field={fieldWithValue} onChange={mockOnChange} />);
    // When there's a value, label should be empty based on the component logic
    const formControl = container.querySelector('.MuiFormControl-root');
    expect(formControl).toBeInTheDocument();
  });

  it('calls onChange when a value is selected', async () => {
    const { container } = render(<SelectInput field={defaultField} onChange={mockOnChange} />);
    
    // Open the Select dropdown
    const selectButton = container.querySelector('.MuiSelect-select');
    fireEvent.mouseDown(selectButton);

    // Wait for the dropdown menu to appear and find the listbox
    const listbox = await screen.findByRole('listbox');
    const optionA = within(listbox).getByText('Option A');
    fireEvent.click(optionA);

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

  it('handles Options string that does not start with [', () => {
    const nonArrayOptions = { ...defaultField, Options: 'not an array' };
    const { container } = render(<SelectInput field={nonArrayOptions} onChange={mockOnChange} />);
    const formControl = container.querySelector('.MuiFormControl-root');
    expect(formControl).toBeInTheDocument();
  });

  it('handles whitespace before JSON array', () => {
    const whitespaceOptions = { ...defaultField, Options: '  ["A", "B"]' };
    const { container } = render(<SelectInput field={whitespaceOptions} onChange={mockOnChange} />);
    const formControl = container.querySelector('.MuiFormControl-root');
    expect(formControl).toBeInTheDocument();
  });
});
