import { describe, test, expect, vi } from 'vitest';
import React from 'react';
import { createRoot, Root } from 'react-dom/client';
import { act } from 'react-dom/test-utils';
import { HtmlToolbar, SNIPPETS } from './HtmlToolbar';
import type { CodeEditorHandle } from '../../../ui/CodeEditor';

let container: HTMLDivElement;
let root: Root;

function render(ui: React.ReactElement) {
  container = document.createElement('div');
  document.body.appendChild(container);
  act(() => {
    root = createRoot(container);
    root.render(ui);
  });
}

function fakeHandle() {
  return { insertAtCursor: vi.fn(), getValue: vi.fn(() => '') } as unknown as CodeEditorHandle;
}

describe('HtmlToolbar', () => {
  test('every snippet button inserts its snippet with its caret offset', () => {
    const handle = fakeHandle();
    const ref = { current: handle } as React.RefObject<CodeEditorHandle>;
    render(<HtmlToolbar editorRef={ref} onFormat={vi.fn()} />);

    for (const snippet of SNIPPETS) {
      const btn = container.querySelector(`[data-snippet="${snippet.label}"]`) as HTMLButtonElement;
      expect(btn, `missing button for ${snippet.label}`).not.toBeNull();
      act(() => { btn.click(); });
      expect(handle.insertAtCursor).toHaveBeenCalledWith(snippet.text, snippet.caret);
    }
  });

  test('the colour input inserts a style attribute at the caret', () => {
    const handle = fakeHandle();
    const ref = { current: handle } as React.RefObject<CodeEditorHandle>;
    render(<HtmlToolbar editorRef={ref} onFormat={vi.fn()} />);

    const colour = container.querySelector('input[type="color"]') as HTMLInputElement;
    colour.value = '#ff8800';
    act(() => { colour.dispatchEvent(new Event('input', { bubbles: true })); });

    expect(handle.insertAtCursor).toHaveBeenCalledWith(' style="color: #ff8800"');
  });

  test('Format calls onFormat', () => {
    const onFormat = vi.fn();
    const ref = { current: fakeHandle() } as React.RefObject<CodeEditorHandle>;
    render(<HtmlToolbar editorRef={ref} onFormat={onFormat} />);
    const btn = container.querySelector('[data-action="format"]') as HTMLButtonElement;
    act(() => { btn.click(); });
    expect(onFormat).toHaveBeenCalledTimes(1);
  });

  test('a null editor ref is a no-op, not a crash', () => {
    const ref = { current: null } as React.RefObject<CodeEditorHandle>;
    render(<HtmlToolbar editorRef={ref} onFormat={vi.fn()} />);
    const btn = container.querySelector('[data-snippet="div"]') as HTMLButtonElement;
    expect(() => act(() => { btn.click(); })).not.toThrow();
  });
});
