import { describe, test, expect, vi, beforeEach, afterEach } from 'vitest';
import React from 'react';
import { createRoot, Root } from 'react-dom/client';
import { act } from 'react-dom/test-utils';

/* MediaStylePanel (via useNodeProp/ArrayPropEditor in ./shared) only needs
   useEditor from @craftjs/core. Mock it following the DOM-harness pattern
   used in Footer.editguard.test.tsx / AssetPicker.test.tsx (no
   @testing-library/react in this repo) so setProp calls can be observed
   without mounting a real <Editor> tree. */
const setPropSpy = vi.fn((_id: string, updater: (p: any) => void) => {
  updater(lastProps);
});
let lastProps: any;

vi.mock('@craftjs/core', () => ({
  useEditor: () => ({ actions: { setProp: setPropSpy } }),
}));

vi.mock('../../../utils/assets', () => ({
  uploadAsset: vi.fn(),
  listAssets: vi.fn(),
}));

import { MediaStylePanel } from './MediaStylePanel';

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 unmount() {
  act(() => { root.unmount(); });
  container.remove();
}

function q<T extends Element = Element>(testId: string): T | null {
  return container.querySelector(`[data-testid="${testId}"]`);
}

function setValue(input: HTMLInputElement, value: string) {
  const setter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value')!.set!;
  setter.call(input, value);
  input.dispatchEvent(new Event('input', { bubbles: true }));
}

beforeEach(() => {
  setPropSpy.mockClear();
});

afterEach(() => {
  if (container) unmount();
});

/**
 * INT: ContentSlider (src/components/sections/ContentSlider.tsx) reads
 * `slide.imageSrc` in both render and toHtml, but the Slides array editor
 * here guarded on `item.image !== undefined` and wrote `image` via
 * AssetPicker's onChange -- a key that ContentSlider never reads. Default
 * slides (`imageSrc:''`, no `image` key) therefore showed NO image picker at
 * all (the guard was never true), and even a manually-added `image` value
 * was a silent no-op on export/render.
 */
describe('MediaStylePanel Slides editor uses imageSrc (INT)', () => {
  test('a slide shaped like defaultSlides (imageSrc present, no `image` key) renders the image AssetPicker', () => {
    lastProps = { slides: [{ type: 'image', imageSrc: '', heading: 'First Slide', text: '', bgColor: '' }] };
    render(<MediaStylePanel selectedId="cs-1" nodeProps={lastProps} />);

    // Before the fix, the guard `item.image !== undefined` was false for
    // this default-shaped slide, so no AssetPicker rendered at all.
    expect(q('asset-picker-compact')).not.toBeNull();
  });

  test('editing the slide image writes imageSrc (not image) via setProp', () => {
    lastProps = { slides: [{ type: 'image', imageSrc: '', heading: 'First Slide', text: '', bgColor: '' }] };
    render(<MediaStylePanel selectedId="cs-1" nodeProps={lastProps} />);

    const urlInput = q<HTMLInputElement>('asset-picker-url-input')!;
    expect(urlInput).not.toBeNull();
    setValue(urlInput, 'https://example.com/slide.jpg');
    act(() => {
      urlInput.dispatchEvent(new FocusEvent('focusout', { bubbles: true }));
    });

    expect(setPropSpy).toHaveBeenCalled();
    const updatedSlide = lastProps.slides[0];
    expect(updatedSlide.imageSrc).toBe('https://example.com/slide.jpg');
    expect(updatedSlide.image).toBeUndefined();
  });

  test('adding a new slide (emptyItem) includes imageSrc, matching defaultSlides shape', () => {
    lastProps = { slides: [] };
    render(<MediaStylePanel selectedId="cs-1" nodeProps={lastProps} />);

    // The "+ Add Item" button for the Slides ArrayPropEditor.
    const addButtons = Array.from(container.querySelectorAll('button')).filter(
      (b) => b.textContent?.includes('Add Item'),
    );
    expect(addButtons.length).toBeGreaterThan(0);
    act(() => {
      addButtons[0].dispatchEvent(new MouseEvent('click', { bubbles: true }));
    });

    expect(setPropSpy).toHaveBeenCalled();
    expect(lastProps.slides).toHaveLength(1);
    expect(lastProps.slides[0]).toHaveProperty('imageSrc');
    expect(lastProps.slides[0].image).toBeUndefined();
  });
});
