import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { createTapConfirm } from './tapconfirm';

describe('createTapConfirm', () => {
  beforeEach(() => vi.useFakeTimers());
  afterEach(() => vi.useRealTimers());

  it('arms a window and reverts after the duration', () => {
    const changes: boolean[] = [];
    const c = createTapConfirm({ durationMs: 2000, onConfirm: () => {}, onChange: (x) => changes.push(x) });
    c.arm();
    expect(c.confirming).toBe(true);
    expect(changes).toEqual([true]);
    vi.advanceTimersByTime(1999);
    expect(c.confirming).toBe(true);
    vi.advanceTimersByTime(1);
    expect(c.confirming).toBe(false);
    expect(changes).toEqual([true, false]);
  });

  it('confirms within the window exactly once and stops the revert timer', () => {
    const onConfirm = vi.fn();
    const c = createTapConfirm({ durationMs: 2000, onConfirm });
    c.arm();
    c.confirm();
    expect(onConfirm).toHaveBeenCalledTimes(1);
    expect(c.confirming).toBe(false);
    vi.advanceTimersByTime(5000); // the revert timer must not fire after a confirm
    expect(onConfirm).toHaveBeenCalledTimes(1);
  });

  it('ignores confirm when the window is not open', () => {
    const onConfirm = vi.fn();
    const c = createTapConfirm({ durationMs: 2000, onConfirm });
    c.confirm();
    expect(onConfirm).not.toHaveBeenCalled();
    expect(c.confirming).toBe(false);
  });

  it('treats arm as idempotent while already confirming', () => {
    const changes: boolean[] = [];
    const c = createTapConfirm({ durationMs: 2000, onConfirm: () => {}, onChange: (x) => changes.push(x) });
    c.arm();
    c.arm();
    expect(changes).toEqual([true]);
  });

  it('cancel closes the window without confirming', () => {
    const onConfirm = vi.fn();
    const c = createTapConfirm({ durationMs: 2000, onConfirm });
    c.arm();
    c.cancel();
    expect(c.confirming).toBe(false);
    vi.advanceTimersByTime(5000);
    expect(onConfirm).not.toHaveBeenCalled();
  });

  it('dispose clears a pending timer without a revert callback', () => {
    const changes: boolean[] = [];
    const c = createTapConfirm({ durationMs: 2000, onConfirm: () => {}, onChange: (x) => changes.push(x) });
    c.arm();
    c.dispose();
    vi.advanceTimersByTime(5000);
    expect(changes).toEqual([true]);
  });
});
