import React, { act } from 'react';
import { createRoot } from 'react-dom/client';
import { afterEach, describe, expect, it, vi } from 'vitest';
import dayjs from 'dayjs';
import EditableCell, {
  editableValuesEqual,
  normalizeEditableValue,
  serializeEditableValue,
} from './index';

let container: HTMLDivElement | null = null;
let root: ReturnType<typeof createRoot> | null = null;

const flush = () => new Promise((resolve) => setTimeout(resolve, 0));

afterEach(async () => {
  if (root) {
    await act(async () => root?.unmount());
  }
  container?.remove();
  root = null;
  container = null;
});

describe('editable cell value mapping', () => {
  it('normalizes and serializes date values', () => {
    const value = normalizeEditableValue('2026-07-21', 'date');
    expect(dayjs.isDayjs(value)).toBe(true);
    expect(serializeEditableValue(value, 'date')).toBe('2026-07-21');
  });

  it('normalizes and serializes date ranges', () => {
    const value = normalizeEditableValue(['2026-07-01', '2026-07-31'], 'date-range');
    expect(serializeEditableValue(value, 'date-range')).toEqual(['2026-07-01', '2026-07-31']);
  });

  it('converts numeric input and preserves zero', () => {
    expect(serializeEditableValue(normalizeEditableValue('12.50', 'money'), 'money')).toBe(12.5);
    expect(serializeEditableValue(0, 'number')).toBe(0);
  });

  it('normalizes empty and multi-select values', () => {
    expect(serializeEditableValue('', 'number')).toBeUndefined();
    expect(normalizeEditableValue(undefined, 'multi-select')).toEqual([]);
  });

  it('compares structured values without reference equality', () => {
    expect(editableValuesEqual([1, 2], [1, 2])).toBe(true);
    expect(editableValuesEqual(' a ', 'a')).toBe(false);
  });
});

describe('editable cell interactions', () => {
  it('saves a single-select value immediately when an option is clicked', async () => {
    const onSave = vi.fn(async () => undefined);
    container = document.createElement('div');
    document.body.appendChild(container);
    root = createRoot(container);

    await act(async () => {
      root?.render(
        React.createElement(
          EditableCell,
          {
            value: 'active',
            editor: 'select',
            options: [
              { value: 'active', label: '启用' },
              { value: 'disabled', label: '停用' },
            ],
            onSave,
          },
          '启用',
        ),
      );
    });

    await act(async () => {
      container?.querySelector('.editable-cell')?.dispatchEvent(
        new MouseEvent('dblclick', { bubbles: true }),
      );
      await flush();
    });

    const options = Array.from(document.querySelectorAll<HTMLElement>('.ant-select-item-option'));
    const disabledOption = options.find((option) => option.textContent?.includes('停用'));
    expect(disabledOption).toBeTruthy();

    await act(async () => {
      disabledOption?.dispatchEvent(new MouseEvent('click', { bubbles: true }));
      await flush();
    });

    expect(onSave).toHaveBeenCalledOnce();
    expect(onSave).toHaveBeenCalledWith('disabled');
    expect(container.querySelector('.editable-cell--editing')).toBeNull();
  });
});
