import { describe, it, expect, beforeEach } from 'vitest';
import { resettable } from './resettable.js';
import { mountHost, connectTrait, spyEvent, resetDOM } from '../test-helpers.js';

function mountInForm(initialValue = 'initial') {
  const form = document.createElement('form');
  document.body.appendChild(form);
  const host = document.createElement('input');
  host.value = initialValue;
  form.appendChild(host);
  return { form, host };
}

describe('resettable', () => {
  beforeEach(resetDOM);

  it('captures initial value on connect; restores it on form reset', () => {
    const { form, host } = mountInForm('original');
    connectTrait(resettable, host);
    host.value = 'modified';
    form.dispatchEvent(new Event('reset', { bubbles: true }));
    expect(host.value).toBe('original');
  });

  it('dispatches reset-applied with the initial value in detail', () => {
    const { form, host } = mountInForm('hello');
    connectTrait(resettable, host);
    const spy = spyEvent(host, 'reset-applied');
    host.value = 'changed';
    form.dispatchEvent(new Event('reset', { bubbles: true }));
    expect(spy.count).toBe(1);
    expect(spy.last.initialValue).toBe('hello');
  });

  it('outside a form: no-op (no throw, no listener)', () => {
    const host = mountHost('input', { value: 'x' });
    expect(() => connectTrait(resettable, host)).not.toThrow();
    expect(host.hasAttribute('data-resettable-active')).toBe(true);
  });

  it('disconnect removes the form listener', () => {
    const { form, host } = mountInForm('a');
    const inst = resettable();
    inst.connect(host);
    inst.disconnect(host);
    host.value = 'b';
    form.dispatchEvent(new Event('reset', { bubbles: true }));
    // After disconnect, the trait should NOT have reset the value.
    expect(host.value).toBe('b');
    expect(host.hasAttribute('data-resettable-active')).toBe(false);
  });

  it('multiple controls in the same form each reset independently', () => {
    const form = document.createElement('form');
    document.body.appendChild(form);
    const a = document.createElement('input'); a.value = 'A';
    const b = document.createElement('input'); b.value = 'B';
    form.appendChild(a); form.appendChild(b);
    resettable().connect(a);
    resettable().connect(b);
    a.value = 'changed-a';
    b.value = 'changed-b';
    form.dispatchEvent(new Event('reset', { bubbles: true }));
    expect(a.value).toBe('A');
    expect(b.value).toBe('B');
  });

  it('boolean controls (host.checked) restore their initial checked state', () => {
    // Synthesize a switch-like host: the only state is a boolean `checked`
    // reactive property — no `value`. Mirrors switch-ui's API.
    const form = document.createElement('form');
    document.body.appendChild(form);
    const host = document.createElement('div');
    host.checked = true;
    form.appendChild(host);

    connectTrait(resettable, host);
    const spy = spyEvent(host, 'reset-applied');

    host.checked = false; // user toggles it off
    form.dispatchEvent(new Event('reset', { bubbles: true }));

    expect(host.checked).toBe(true);
    expect(spy.count).toBe(1);
    expect(spy.last.initialValue).toBe(true);
  });

  it('boolean controls starting unchecked stay unchecked after reset', () => {
    const form = document.createElement('form');
    document.body.appendChild(form);
    const host = document.createElement('div');
    host.checked = false;
    form.appendChild(host);

    connectTrait(resettable, host);
    host.checked = true;
    form.dispatchEvent(new Event('reset', { bubbles: true }));
    expect(host.checked).toBe(false);
  });
});
