/* @vitest-environment jsdom */

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

import type {
  GenerateDialogState,
  SpecFormValues,
  UploadTarget,
} from './ImageCanvasEditorTypes';
import { ImageCanvasSpecGenerationPanelView } from './ImageCanvasSpecGenerationPanelView';

function createSpecDialog(
  patch: Partial<GenerateDialogState> = {},
): GenerateDialogState {
  return {
    mode: 'spec',
    prompt: '',
    status: 'idle',
    specType: 'character',
    specValues: {
      playSetting: 'RPG玩法',
      artStyle: '像素风',
      bodyRatio: '3',
      characterView: '右向斜侧身站姿',
      customPrompt: '',
    },
    ...patch,
  };
}

function renderPanel({
  dialog,
  onUpdateSpecFormValue = vi.fn(),
  onRequestUpload = vi.fn(),
  onSubmit = vi.fn(),
}: {
  dialog: GenerateDialogState;
  onUpdateSpecFormValue?: (key: keyof SpecFormValues, value: string) => void;
  onRequestUpload?: (target: UploadTarget) => void;
  onSubmit?: (dialog: GenerateDialogState) => void;
}) {
  render(
    <ImageCanvasSpecGenerationPanelView
      dialog={dialog}
      style={{ left: 10, top: 20 }}
      onUpdateSpecFormValue={onUpdateSpecFormValue}
      onRequestUpload={onRequestUpload}
      onSubmit={onSubmit}
    />,
  );
}

describe('ImageCanvasSpecGenerationPanelView', () => {
  it('renders character spec fields and forwards updates', () => {
    const updateSpecFormValue = vi.fn();
    renderPanel({
      dialog: createSpecDialog(),
      onUpdateSpecFormValue: updateSpecFormValue,
    });

    fireEvent.change(screen.getByLabelText('玩法设定'), {
      target: { value: '战棋玩法' },
    });
    fireEvent.change(screen.getByLabelText('美术风格'), {
      target: { value: '水彩' },
    });
    fireEvent.change(screen.getByLabelText('头身比'), {
      target: { value: '5' },
    });
    fireEvent.change(screen.getByLabelText('角色视角'), {
      target: { value: '左向三分之二侧身站姿' },
    });

    expect(updateSpecFormValue).toHaveBeenCalledWith('playSetting', '战棋玩法');
    expect(updateSpecFormValue).toHaveBeenCalledWith('artStyle', '水彩');
    expect(updateSpecFormValue).toHaveBeenCalledWith('bodyRatio', '5');
    expect(updateSpecFormValue).toHaveBeenCalledWith(
      'characterView',
      '左向三分之二侧身站姿',
    );
  });

  it('renders custom prompt and hides reference upload for icon specs', () => {
    const updateSpecFormValue = vi.fn();
    renderPanel({
      dialog: createSpecDialog({
        specType: 'custom',
        specValues: {
          playSetting: '',
          artStyle: '',
          bodyRatio: '3',
          characterView: '',
          customPrompt: '自定义提示',
        },
      }),
      onUpdateSpecFormValue: updateSpecFormValue,
    });

    fireEvent.change(screen.getByLabelText('自定义规范提示词'), {
      target: { value: '新的规范提示' },
    });

    expect(updateSpecFormValue).toHaveBeenCalledWith(
      'customPrompt',
      '新的规范提示',
    );

    cleanup();
    renderPanel({ dialog: createSpecDialog({ specType: 'icon' }) });

    expect(screen.queryByText('添加参考图')).toBeNull();
  });

  it('requests reference upload and submits while idle', () => {
    const requestUpload = vi.fn();
    const submitSpec = vi.fn();
    const dialog = createSpecDialog();
    renderPanel({
      dialog,
      onRequestUpload: requestUpload,
      onSubmit: submitSpec,
    });

    fireEvent.click(screen.getByRole('button', { name: '添加参考图' }));
    fireEvent.click(screen.getByRole('button', { name: '提交生成规范' }));

    expect(requestUpload).toHaveBeenCalledWith('spec-reference');
    expect(submitSpec).toHaveBeenCalledWith(dialog);
  });

  it('disables controls while generating and renders failure state', () => {
    const submitSpec = vi.fn();
    const { rerender } = render(
      <ImageCanvasSpecGenerationPanelView
        dialog={createSpecDialog({ status: 'generating' })}
        style={{ left: 10, top: 20 }}
        onUpdateSpecFormValue={vi.fn()}
        onRequestUpload={vi.fn()}
        onSubmit={submitSpec}
      />,
    );

    fireEvent.click(screen.getByRole('button', { name: '提交生成规范' }));

    expect((screen.getByLabelText('玩法设定') as HTMLInputElement).disabled).toBe(
      true,
    );
    expect(submitSpec).not.toHaveBeenCalled();

    rerender(
      <ImageCanvasSpecGenerationPanelView
        dialog={createSpecDialog({
          status: 'failed',
          errorMessage: '生成失败',
        })}
        style={{ left: 10, top: 20 }}
        onUpdateSpecFormValue={vi.fn()}
        onRequestUpload={vi.fn()}
        onSubmit={submitSpec}
      />,
    );

    expect(screen.getByRole('alert').textContent).toContain('生成失败');
  });
});
