import { fireEvent, render, screen, within } from '@testing-library/react';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { resetStore } from '../test/storeTestUtils';
import { useStore } from '../store/useStore';
import { OntologyInspector } from './OntologyInspector';

const apiMock = vi.hoisted(() => ({
  analyzeMask: vi.fn(),
  updateTemplate: vi.fn(),
}));

vi.mock('../lib/api', () => ({
  analyzeMask: apiMock.analyzeMask,
  updateTemplate: apiMock.updateTemplate,
}));

describe('OntologyInspector', () => {
  beforeEach(() => {
    resetStore();
    vi.clearAllMocks();
    apiMock.analyzeMask.mockResolvedValue({
      confidence: 0.82,
      confidence_source: 'model_score',
      topology_anchor_count: 4,
      topology_anchors: [],
      area: 0.1,
      bbox: [0, 0, 0.1, 0.1],
      source: 'sam2.1_hiera_tiny',
      message: '已读取后端几何属性',
    });
    useStore.setState({
      templates: [
        {
          id: 't1',
          name: '腹腔镜模板',
          classes: [
            { id: 'c1', name: '胆囊', color: '#ff0000', zIndex: 20, category: '器官' },
            { id: 'c2', name: '肝脏', color: '#00ff00', zIndex: 10, category: '器官' },
          ],
          rules: [],
        },
      ],
    });
  });

  it('shows template classes and changes the active template', () => {
    render(<OntologyInspector />);

    fireEvent.change(screen.getByRole('combobox'), { target: { value: 't1' } });

    expect(useStore.getState().activeTemplateId).toBe('t1');
    expect(screen.getByText('胆囊')).toBeInTheDocument();
    expect(screen.getByText('肝脏')).toBeInTheDocument();
  });

  it('selects a concrete class for subsequent masks', () => {
    render(<OntologyInspector />);

    fireEvent.click(screen.getByText('胆囊'));

    expect(useStore.getState().activeClassId).toBe('c1');
    expect(useStore.getState().activeClass).toEqual(expect.objectContaining({
      id: 'c1',
      name: '胆囊',
      zIndex: 20,
    }));
  });

  it('applies the selected class to currently selected masks', () => {
    useStore.setState({
      selectedMaskIds: ['m1'],
      masks: [
        {
          id: 'm2',
          frameId: 'frame-1',
          pathData: 'M 10 10 Z',
          label: '未选区域',
          color: '#ffffff',
          saveStatus: 'draft',
        },
        {
          id: 'm1',
          annotationId: '99',
          frameId: 'frame-1',
          pathData: 'M 0 0 Z',
          label: '旧标签',
          color: '#06b6d4',
          saveStatus: 'saved',
          saved: true,
        },
      ],
    });

    render(<OntologyInspector />);
    fireEvent.click(screen.getByText('肝脏'));

    expect(useStore.getState().activeClassId).toBe('c2');
    expect(useStore.getState().masks.map((mask) => mask.id)).toEqual(['m2', 'm1']);
    expect(useStore.getState().masks[1]).toEqual(expect.objectContaining({
      templateId: 't1',
      classId: 'c2',
      className: '肝脏',
      classZIndex: 10,
      label: '肝脏',
      color: '#00ff00',
      saveStatus: 'dirty',
      saved: false,
    }));
    expect(screen.getByText('当前选中区域:')).toBeInTheDocument();
    expect(screen.getByText('1')).toBeInTheDocument();
  });

  it('persists custom classes to the active backend template', async () => {
    apiMock.updateTemplate.mockResolvedValueOnce({
      id: 't1',
      name: '腹腔镜模板',
      classes: [
        { id: 'c1', name: '胆囊', color: '#ff0000', zIndex: 20, category: '器官' },
        { id: 'c2', name: '肝脏', color: '#00ff00', zIndex: 10, category: '器官' },
        { id: 'custom-1', name: '新局部分类', color: '#06b6d4', zIndex: 30, category: '自定义' },
      ],
      rules: [],
    });

    render(<OntologyInspector />);
    fireEvent.change(screen.getByRole('combobox'), { target: { value: 't1' } });
    const customSection = screen.getByText('自定义分类').parentElement!;
    fireEvent.click(within(customSection).getByRole('button'));
    fireEvent.change(screen.getByPlaceholderText('分类名称'), { target: { value: '新局部分类' } });
    fireEvent.keyDown(screen.getByPlaceholderText('分类名称'), { key: 'Enter' });

    expect(await screen.findByText('自定义分类已保存到后端模板')).toBeInTheDocument();
    expect(apiMock.updateTemplate).toHaveBeenCalledWith('t1', expect.objectContaining({
      classes: expect.arrayContaining([expect.objectContaining({ name: '新局部分类', category: '自定义' })]),
    }));
    expect(useStore.getState().activeClass).toEqual(expect.objectContaining({ name: '新局部分类' }));
    expect(useStore.getState().templates[0].classes).toHaveLength(3);
  });

  it('loads selected mask properties from the backend analyzer', async () => {
    useStore.setState({
      frames: [{ id: 'frame-1', projectId: 'p1', index: 0, url: '/1.jpg', width: 100, height: 100 }],
      selectedMaskIds: ['m1'],
      masks: [
        {
          id: 'm1',
          frameId: 'frame-1',
          pathData: 'M 0 0 Z',
          label: '胆囊',
          color: '#ff0000',
          segmentation: [[10, 10, 20, 10, 20, 20]],
          metadata: { source: 'sam2.1_hiera_tiny', score: 0.82 },
        },
      ],
    });

    render(<OntologyInspector />);

    expect(await screen.findByText('0.8200')).toBeInTheDocument();
    expect(screen.getByText('4 节点')).toBeInTheDocument();
    fireEvent.click(screen.getByRole('button', { name: '重新提取拓扑锚点' }));
    expect(apiMock.analyzeMask).toHaveBeenLastCalledWith(
      expect.objectContaining({ id: 'm1' }),
      expect.objectContaining({ id: 'frame-1' }),
      { extractSkeleton: true },
    );
  });
});
