/* @vitest-environment jsdom */

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

import { ApiClientError } from '../../services/apiClient';
import { useImageCanvasEditorChrome } from './useImageCanvasEditorChrome';

const renameEditorProjectMock = vi.hoisted(() => vi.fn());

vi.mock('../../services/image-editor/editorProjectClient', async () => {
  const actual = await vi.importActual<
    typeof import('../../services/image-editor/editorProjectClient')
  >('../../services/image-editor/editorProjectClient');
  return {
    ...actual,
    renameEditorProject: renameEditorProjectMock,
  };
});

function ChromeHarness({
  openEditorLoginModal = vi.fn(),
}: {
  openEditorLoginModal?: (postLoginAction?: (() => void) | null) => void;
}) {
  const chrome = useImageCanvasEditorChrome({ openEditorLoginModal });

  return (
    <div>
      <span data-testid="title">{chrome.projectTitle}</span>
      <span data-testid="rename-value">{chrome.projectRenameValue}</span>
      <span data-testid="renaming">{String(chrome.isRenamingProject)}</span>
      <span data-testid="saving">{String(chrome.isProjectRenameSaving)}</span>
      <span data-testid="rename-error">{chrome.projectRenameError ?? '-'}</span>
      <span data-testid="sidebar">{chrome.activeSidebarPanel ?? '-'}</span>
      <span data-testid="tool">{chrome.activeTool}</span>
      <span data-testid="zoom">{String(chrome.isZoomMenuOpen)}</span>
      <span data-testid="background-open">
        {String(chrome.isBackgroundSettingsOpen)}
      </span>
      <span data-testid="minimap">{String(chrome.isMinimapOpen)}</span>
      <span data-testid="background-color">
        {chrome.canvasBackgroundColor}
      </span>
      <span data-testid="background-hex">
        {chrome.canvasBackgroundHexValue}
      </span>
      <button type="button" onClick={chrome.startProjectRename}>
        start rename
      </button>
      <button type="button" onClick={chrome.cancelProjectRename}>
        cancel rename
      </button>
      <button
        type="button"
        onClick={() => chrome.submitProjectRename('project-1')}
      >
        submit rename
      </button>
      <button
        type="button"
        onClick={() => chrome.submitProjectRename(null)}
      >
        submit without project
      </button>
      <button
        type="button"
        onClick={() => chrome.setProjectRenameValue('  新项目  ')}
      >
        set rename
      </button>
      <button
        type="button"
        onClick={() => chrome.setProjectRenameValue('   ')}
      >
        blank rename
      </button>
      <button type="button" onClick={() => chrome.setProjectTitle('已有项目')}>
        set title
      </button>
      <button type="button" onClick={() => chrome.setActiveTool('hand')}>
        set hand
      </button>
      <button type="button" onClick={() => chrome.toggleSidebarPanel('assets')}>
        toggle assets
      </button>
      <button type="button" onClick={() => chrome.toggleSidebarPanel('layers')}>
        toggle layers
      </button>
      <button type="button" onClick={chrome.toggleZoomMenu}>
        toggle zoom
      </button>
      <button type="button" onClick={chrome.toggleBackgroundSettings}>
        toggle background
      </button>
      <button type="button" onClick={chrome.toggleMinimap}>
        toggle minimap
      </button>
      <button type="button" onClick={chrome.closeEditorChromePanels}>
        close panels
      </button>
      <button
        type="button"
        onClick={() => chrome.applyCanvasBackgroundColor('#abc')}
      >
        apply short hex
      </button>
      <button
        type="button"
        onClick={() => chrome.handleCanvasBackgroundHexChange('#not-a-color')}
      >
        invalid hex
      </button>
      <button
        type="button"
        onClick={() => chrome.handleCanvasBackgroundHexChange('#ffffff')}
      >
        valid hex
      </button>
    </div>
  );
}

describe('useImageCanvasEditorChrome', () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  it('renames projects and resets rename state from the saved title', async () => {
    renameEditorProjectMock.mockResolvedValueOnce({
      projectId: 'project-1',
      title: '后端项目名',
      viewport: { x: 0, y: 0, scale: 1 },
      layers: [],
      resources: [],
      updatedAt: '2026-06-17T00:00:00.000Z',
    });
    render(<ChromeHarness />);

    fireEvent.click(screen.getByRole('button', { name: 'set title' }));
    fireEvent.click(screen.getByRole('button', { name: 'start rename' }));
    expect(screen.getByTestId('rename-value').textContent).toBe('已有项目');

    fireEvent.click(screen.getByRole('button', { name: 'set rename' }));
    fireEvent.click(screen.getByRole('button', { name: 'submit rename' }));
    expect(screen.getByTestId('saving').textContent).toBe('true');

    await waitFor(() => {
      expect(renameEditorProjectMock).toHaveBeenCalledWith(
        'project-1',
        '新项目',
      );
    });
    expect(screen.getByTestId('title').textContent).toBe('后端项目名');
    expect(screen.getByTestId('rename-value').textContent).toBe('后端项目名');
    expect(screen.getByTestId('renaming').textContent).toBe('false');
    expect(screen.getByTestId('saving').textContent).toBe('false');
  });

  it('validates rename input and opens login on rename auth errors', async () => {
    const openEditorLoginModal = vi.fn();
    renameEditorProjectMock.mockRejectedValueOnce(
      new ApiClientError({
        message: '未授权访问',
        status: 401,
        code: 'UNAUTHORIZED',
      }),
    );
    render(<ChromeHarness openEditorLoginModal={openEditorLoginModal} />);

    fireEvent.click(screen.getByRole('button', { name: 'blank rename' }));
    fireEvent.click(screen.getByRole('button', { name: 'submit rename' }));
    expect(screen.getByTestId('rename-error').textContent).toBe(
      '项目名称不能为空',
    );
    expect(renameEditorProjectMock).not.toHaveBeenCalled();

    fireEvent.click(screen.getByRole('button', { name: 'set rename' }));
    fireEvent.click(screen.getByRole('button', { name: 'submit rename' }));

    await waitFor(() => {
      expect(openEditorLoginModal).toHaveBeenCalledTimes(1);
    });
    expect(screen.getByTestId('rename-error').textContent).toBe('未授权访问');
  });

  it('manages background colors and chrome panel toggles', () => {
    render(<ChromeHarness />);

    fireEvent.click(screen.getByRole('button', { name: 'apply short hex' }));
    expect(screen.getByTestId('background-color').textContent).toBe('#aabbcc');
    expect(screen.getByTestId('background-hex').textContent).toBe('#aabbcc');

    fireEvent.click(screen.getByRole('button', { name: 'invalid hex' }));
    expect(screen.getByTestId('background-color').textContent).toBe('#aabbcc');
    expect(screen.getByTestId('background-hex').textContent).toBe(
      '#not-a-color',
    );

    fireEvent.click(screen.getByRole('button', { name: 'valid hex' }));
    expect(screen.getByTestId('background-color').textContent).toBe('#ffffff');
    expect(screen.getByTestId('background-hex').textContent).toBe('#ffffff');

    fireEvent.click(screen.getByRole('button', { name: 'toggle assets' }));
    expect(screen.getByTestId('sidebar').textContent).toBe('-');
    fireEvent.click(screen.getByRole('button', { name: 'toggle layers' }));
    expect(screen.getByTestId('sidebar').textContent).toBe('layers');
    fireEvent.click(screen.getByRole('button', { name: 'toggle zoom' }));
    fireEvent.click(screen.getByRole('button', { name: 'toggle background' }));
    fireEvent.click(screen.getByRole('button', { name: 'toggle minimap' }));
    fireEvent.click(screen.getByRole('button', { name: 'set hand' }));
    expect(screen.getByTestId('zoom').textContent).toBe('true');
    expect(screen.getByTestId('background-open').textContent).toBe('true');
    expect(screen.getByTestId('minimap').textContent).toBe('false');
    expect(screen.getByTestId('tool').textContent).toBe('hand');

    act(() => {
      screen.getByRole('button', { name: 'close panels' }).click();
    });
    expect(screen.getByTestId('sidebar').textContent).toBe('-');
    expect(screen.getByTestId('zoom').textContent).toBe('false');
    expect(screen.getByTestId('background-open').textContent).toBe('false');
  });
});
