// @vitest-environment jsdom
/**
 * Component tests for ExecutionForm (settings batch A).
 *
 * Focus: the comma-separated "Backoff Seconds" serialization (split, trim,
 * Number, filter NaN), number coercion for concurrency/maxMovements with the
 * empty -> undefined contract, and ENV-override disabling of the concurrency
 * field.
 */
import '../../test/dom-setup';
import { describe, it, expect, vi } from 'vitest';
import { screen, fireEvent } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { renderWithProviders, renderStatefulForm } from '../../test/render-helpers';
import { ExecutionForm } from './ExecutionForm';

function render(config: any = {}, overriddenByEnv: Record<string, boolean> = {}) {
  const onChange = vi.fn();
  renderWithProviders(
    <ExecutionForm config={config} onChange={onChange} overriddenByEnv={overriddenByEnv} />,
  );
  return { onChange };
}

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

describe('ExecutionForm', () => {
  it('renders the default backoff seconds joined as a comma string', () => {
    render({});
    const backoff = screen.getByDisplayValue('60, 300, 900');
    expect(backoff).toBeInTheDocument();
  });

  it('serializes concurrency to a number and undefined when emptied', async () => {
    const { onChange, getConfig } = renderStateful({ concurrency: 4 });
    const concurrency = screen.getAllByRole('spinbutton')[0];
    await userEvent.clear(concurrency);
    await userEvent.type(concurrency, '2');
    expect(getConfig().concurrency).toBe(2);
    await userEvent.clear(concurrency);
    expect(getConfig().concurrency).toBeUndefined();
    expect(onChange).toHaveBeenLastCalledWith('concurrency', undefined);
  });

  it('serializes backoff seconds: split on comma, trim, Number, drop NaN', () => {
    // The field is a controlled text input that re-serializes to a number[] on
    // every change; fire ONE change with the whole value (like a paste) so the
    // parse is exercised on the complete string. Includes whitespace + a
    // non-numeric token that must be dropped.
    const { getConfig } = renderStateful({ retry: { backoffSeconds: [60] } });
    const backoff = screen.getByDisplayValue('60');
    fireEvent.change(backoff, { target: { value: '10, 20 , abc, 30' } });
    expect(getConfig().retry.backoffSeconds).toEqual([10, 20, 30]);
  });

  it('disables the concurrency field when overridden by env', () => {
    render({ concurrency: 4 }, { concurrency: true });
    const concurrency = screen.getAllByRole('spinbutton')[0] as HTMLInputElement;
    expect(concurrency).toBeDisabled();
  });
});
