// @vitest-environment jsdom
/**
 * Component tests for SafetyForm (settings batch A).
 *
 * Focus: number coercion (text input -> Number), boolean checkbox toggles,
 * the bash-sandbox <select>, the nested historySummarization.* path, and the
 * "enabled !== false" default-on semantics for history summarization.
 *
 * i18n is NOT initialized in the test env, so react-i18next's t() returns the
 * raw key — fine for behavior tests (we assert on roles/values, not labels).
 */
import '../../test/dom-setup';
import { describe, it, expect, vi } from 'vitest';
import { screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { renderWithProviders, renderStatefulForm } from '../../test/render-helpers';
import { SafetyForm } from './SafetyForm';

function render(config: any = { safety: {} }) {
  const onChange = vi.fn();
  renderWithProviders(<SafetyForm config={config} onChange={onChange} overriddenByEnv={{}} />);
  return { onChange };
}

function renderStateful(config: any = { safety: {} }) {
  const onChange = vi.fn();
  const utils = renderStatefulForm(SafetyForm, config, { onChangeSpy: onChange });
  return { onChange, ...utils };
}

describe('SafetyForm', () => {
  it('renders with empty safety config (defaults visible)', () => {
    render({ safety: {} });
    // Max Iterations default 200 shown in the first number field.
    const numbers = screen.getAllByRole('spinbutton') as HTMLInputElement[];
    expect(numbers[0]).toHaveValue(200);
    // bashSandbox select defaults to 'auto'
    expect(screen.getByRole('combobox')).toHaveValue('auto');
  });

  it('coerces a typed number field to a Number via onChange', async () => {
    const { onChange, getConfig } = renderStateful({ safety: { maxIterations: 200 } });
    const numbers = screen.getAllByRole('spinbutton');
    await userEvent.clear(numbers[0]);
    await userEvent.type(numbers[0], '7');
    // Live config reflects a real (numeric) value, not a string.
    expect(getConfig().safety.maxIterations).toBe(7);
    expect(onChange).toHaveBeenCalledWith('safety.maxIterations', expect.any(Number));
  });

  it('serializes promptGuardRatio as undefined when cleared (empty -> undefined)', async () => {
    const { onChange } = render({ safety: { promptGuardRatio: 0.8 } });
    // promptGuardRatio is the 4th number input.
    const numbers = screen.getAllByRole('spinbutton');
    await userEvent.clear(numbers[3]);
    expect(onChange).toHaveBeenLastCalledWith('safety.promptGuardRatio', undefined);
  });

  it('toggles bashUnrestricted checkbox to a boolean', async () => {
    const { onChange } = render({ safety: { bashUnrestricted: false } });
    const checkboxes = screen.getAllByRole('checkbox') as HTMLInputElement[];
    // bashUnrestricted is the first checkbox.
    await userEvent.click(checkboxes[0]);
    expect(onChange).toHaveBeenCalledWith('safety.bashUnrestricted', true);
  });

  it('writes the nested historySummarization path and treats enabled as default-on', async () => {
    // enabled defaults to true (checked) when undefined: checked={enabled !== false}.
    const { onChange } = render({ safety: {} });
    const checkboxes = screen.getAllByRole('checkbox') as HTMLInputElement[];
    // history enabled is the 3rd checkbox (bashUnrestricted, bashAllowNetwork, historyEnabled).
    const historyToggle = checkboxes[2];
    expect(historyToggle).toBeChecked();
    await userEvent.click(historyToggle);
    expect(onChange).toHaveBeenCalledWith('safety.historySummarization.enabled', false);
  });

  it('changes the bash sandbox select value', async () => {
    const { onChange } = render({ safety: { bashSandbox: 'auto' } });
    await userEvent.selectOptions(screen.getByRole('combobox'), 'always');
    expect(onChange).toHaveBeenCalledWith('safety.bashSandbox', 'always');
  });
});
