/* @vitest-environment jsdom */

import { fireEvent, render, screen } from '@testing-library/react';
import { useState } from 'react';
import { describe, expect, it, vi } from 'vitest';

import type {
  CanvasContextMenuState,
  CanvasLayer,
} from './ImageCanvasEditorTypes';
import { useImageCanvasLayerCommands } from './useImageCanvasLayerCommands';

function createLayer(id: string, x: number, zIndex: number): CanvasLayer {
  return {
    id,
    resourceId: `resource-${id}`,
    title: id,
    src: `data:image/png;base64,${id}`,
    x,
    y: 20,
    width: 100,
    height: 80,
    originalWidth: 100,
    originalHeight: 80,
    zIndex,
    sourceType: 'uploaded',
  };
}

function LayerCommandsHarness({
  exportLayerImage = vi.fn(),
  onDeleteLayerSideEffects = vi.fn(),
}: {
  exportLayerImage?: (layer: CanvasLayer | null) => void;
  onDeleteLayerSideEffects?: (layerId: string) => void;
}) {
  const [layers, setLayers] = useState<CanvasLayer[]>([
    createLayer('first', 10, 1),
    createLayer('second', 160, 2),
    createLayer('third', 310, 3),
  ]);
  const [selectedLayerId, setSelectedLayerId] = useState<string | null>(
    'first',
  );
  const [selectedLayerIds, setSelectedLayerIds] = useState<string[]>([
    'first',
    'second',
  ]);
  const [metadataLayer, setMetadataLayer] = useState<CanvasLayer | null>(
    layers[0] ?? null,
  );
  const [hoveredLayerId, setHoveredLayerId] = useState<string | null>('first');
  const [contextMenu, setContextMenu] = useState<CanvasContextMenuState | null>(
    {
      kind: 'layer',
      layerId: 'first',
      x: 0,
      y: 0,
      canvasPoint: { x: 0, y: 0 },
    },
  );
  const [historyCount, setHistoryCount] = useState(0);
  const [imageContextClosedCount, setImageContextClosedCount] = useState(0);
  const [activeTool, setActiveTool] = useState('shape');

  const selectSingleLayer = (layerId: string | null) => {
    setSelectedLayerId(layerId);
    setSelectedLayerIds(layerId ? [layerId] : []);
  };

  const commands = useImageCanvasLayerCommands({
    layers,
    contextMenu,
    selectedLayerId,
    selectedLayerIds,
    setLayers,
    setSelectedLayerId,
    setSelectedLayerIds,
    setHoveredLayerId,
    setMetadataLayer,
    setContextMenu,
    setImageContextMenu: () =>
      setImageContextClosedCount((currentCount) => currentCount + 1),
    setActiveTool,
    captureCanvasHistory: () =>
      setHistoryCount((currentCount) => currentCount + 1),
    selectSingleLayer,
    onDeleteLayerSideEffects,
    exportLayerImage,
  });

  return (
    <div>
      <span data-testid="layers">
        {layers
          .map(
            (layer) =>
              `${layer.id}:${layer.title}:${layer.x}:${layer.zIndex}:${layer.groupId ?? '-'}:${layer.hidden ? 'hidden' : 'shown'}:${layer.locked ? 'locked' : 'open'}:${layer.flipX ? 'flipX' : '-'}:${layer.flipY ? 'flipY' : '-'}`,
          )
          .join('|')}
      </span>
      <span data-testid="selection">
        {selectedLayerId ?? '-'}:{selectedLayerIds.join(',')}
      </span>
      <span data-testid="metadata">{metadataLayer?.id ?? '-'}</span>
      <span data-testid="hovered">{hoveredLayerId ?? '-'}</span>
      <span data-testid="context">{contextMenu ? 'open' : 'closed'}</span>
      <span data-testid="history">{historyCount}</span>
      <span data-testid="image-context-closed">
        {imageContextClosedCount}
      </span>
      <span data-testid="tool">{activeTool}</span>
      <span data-testid="clipboard">
        {commands.canvasClipboard
          ? `${commands.canvasClipboard.mode}:${commands.canvasClipboard.layers.length}`
          : '-'}
      </span>
      <button type="button" onClick={() => commands.copyContextLayers()}>
        复制
      </button>
      <button
        type="button"
        onClick={() => commands.copyContextLayers({ cut: true })}
      >
        剪切
      </button>
      <button
        type="button"
        onClick={() => commands.pasteCanvasClipboard({ x: 500, y: 600 })}
      >
        粘贴
      </button>
      <button type="button" onClick={() => commands.duplicateContextLayers()}>
        创建副本
      </button>
      <button type="button" onClick={() => commands.moveContextLayers('top')}>
        置顶
      </button>
      <button type="button" onClick={() => commands.groupContextLayers()}>
        创建组
      </button>
      <button type="button" onClick={() => commands.ungroupContextLayers()}>
        解除组
      </button>
      <button
        type="button"
        onClick={() => commands.toggleContextLayerVisibility()}
      >
        显隐
      </button>
      <button type="button" onClick={() => commands.toggleContextLayerLock()}>
        锁定
      </button>
      <button type="button" onClick={() => commands.flipContextLayers('x')}>
        翻转
      </button>
      <button type="button" onClick={() => commands.deleteContextLayers()}>
        删除右键目标
      </button>
      <button type="button" onClick={() => commands.deleteSelectedLayer()}>
        删除选中
      </button>
      <button type="button" onClick={() => commands.deleteLayerById('first')}>
        删除单图
      </button>
      <button type="button" onClick={() => commands.groupSelectedLayers()}>
        选中打组
      </button>
      <button type="button" onClick={() => commands.exportContextLayer()}>
        导出
      </button>
      <button
        type="button"
        onClick={() =>
          setContextMenu({
            kind: 'layer',
            layerId: 'third',
            x: 0,
            y: 0,
            canvasPoint: { x: 0, y: 0 },
          })
        }
      >
        右键第三层
      </button>
      <button
        type="button"
        onClick={() => {
          setSelectedLayerId('third');
          setSelectedLayerIds(['third']);
        }}
      >
        只选第三层
      </button>
    </div>
  );
}

describe('useImageCanvasLayerCommands', () => {
  it('copies, cuts, and pastes context layers with history and selection updates', () => {
    render(<LayerCommandsHarness />);

    fireEvent.click(screen.getByRole('button', { name: '复制' }));
    expect(screen.getByTestId('clipboard').textContent).toBe('copy:2');
    expect(screen.getByTestId('context').textContent).toBe('closed');

    fireEvent.click(screen.getByRole('button', { name: '粘贴' }));
    expect(screen.getByTestId('layers').textContent).toContain(
      'first 副本:500:4',
    );
    expect(screen.getByTestId('layers').textContent).toContain(
      'second 副本:650:5',
    );
    expect(screen.getByTestId('selection').textContent).toContain(
      'layer-copy-',
    );
    expect(screen.getByTestId('tool').textContent).toBe('select');

    fireEvent.click(screen.getByRole('button', { name: '右键第三层' }));
    fireEvent.click(screen.getByRole('button', { name: '只选第三层' }));
    fireEvent.click(screen.getByRole('button', { name: '剪切' }));

    expect(screen.getByTestId('clipboard').textContent).toBe('cut:1');
    expect(screen.getByTestId('layers').textContent).not.toContain('third');
    expect(screen.getByTestId('selection').textContent).toBe('-:');
    expect(Number(screen.getByTestId('history').textContent)).toBeGreaterThan(
      1,
    );
  });

  it('applies layer commands and clears menus without owning menu positioning', () => {
    const exportLayerImage = vi.fn();
    render(<LayerCommandsHarness exportLayerImage={exportLayerImage} />);

    fireEvent.click(screen.getByRole('button', { name: '创建组' }));
    expect(screen.getByTestId('layers').textContent).toContain('layer-group-');

    fireEvent.click(screen.getByRole('button', { name: '右键第三层' }));
    fireEvent.click(screen.getByRole('button', { name: '显隐' }));
    expect(screen.getByTestId('layers').textContent).toContain(':hidden:');

    fireEvent.click(screen.getByRole('button', { name: '右键第三层' }));
    fireEvent.click(screen.getByRole('button', { name: '锁定' }));
    expect(screen.getByTestId('layers').textContent).toContain(':locked:');

    fireEvent.click(screen.getByRole('button', { name: '右键第三层' }));
    fireEvent.click(screen.getByRole('button', { name: '翻转' }));
    expect(screen.getByTestId('layers').textContent).toContain(':flipX:');

    fireEvent.click(screen.getByRole('button', { name: '右键第三层' }));
    fireEvent.click(screen.getByRole('button', { name: '导出' }));
    expect(exportLayerImage).toHaveBeenCalledWith(
      expect.objectContaining({ id: 'third' }),
    );
    expect(screen.getByTestId('context').textContent).toBe('closed');
  });

  it('deletes selected and direct layers while running delete side effects', () => {
    const onDeleteLayerSideEffects = vi.fn();
    render(
      <LayerCommandsHarness
        onDeleteLayerSideEffects={onDeleteLayerSideEffects}
      />,
    );

    fireEvent.click(screen.getByRole('button', { name: '删除选中' }));

    expect(screen.getByTestId('layers').textContent).not.toContain('first');
    expect(screen.getByTestId('layers').textContent).not.toContain('second');
    expect(screen.getByTestId('selection').textContent).toBe('third:third');
    expect(screen.getByTestId('metadata').textContent).toBe('-');
    expect(screen.getByTestId('image-context-closed').textContent).toBe('1');
    expect(onDeleteLayerSideEffects).toHaveBeenCalledWith('first');
    expect(onDeleteLayerSideEffects).toHaveBeenCalledWith('second');

    fireEvent.click(screen.getByRole('button', { name: '删除单图' }));
    expect(screen.getByTestId('image-context-closed').textContent).toBe('2');
  });
});
