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

const apiMock = vi.hoisted(() => ({
  getAdminUsers: vi.fn(),
  getAuditLogs: vi.fn(),
  createAdminUser: vi.fn(),
  updateAdminUser: vi.fn(),
  deleteAdminUser: vi.fn(),
  resetDemoFactory: vi.fn(),
}));

vi.mock('../lib/api', () => ({
  getAdminUsers: apiMock.getAdminUsers,
  getAuditLogs: apiMock.getAuditLogs,
  createAdminUser: apiMock.createAdminUser,
  updateAdminUser: apiMock.updateAdminUser,
  deleteAdminUser: apiMock.deleteAdminUser,
  resetDemoFactory: apiMock.resetDemoFactory,
}));

describe('UserAdmin', () => {
  beforeEach(() => {
    resetStore();
    vi.clearAllMocks();
    useStore.setState({ currentUser: { id: 1, username: 'admin', role: 'admin' } });
    apiMock.getAdminUsers.mockResolvedValue([
      { id: 1, username: 'admin', role: 'admin', is_active: 1 },
      { id: 2, username: 'doctor', role: 'annotator', is_active: 1 },
    ]);
    apiMock.getAuditLogs.mockResolvedValue([
      {
        id: 1,
        actor_user_id: 1,
        action: 'admin.user_created',
        target_type: 'user',
        target_id: '2',
        detail: { username: 'doctor' },
        created_at: '2026-05-02T00:00:00Z',
      },
    ]);
  });

  it('loads users and audit logs', async () => {
    render(<UserAdmin />);

    expect(await screen.findByText('doctor')).toBeInTheDocument();
    expect(screen.getByText('admin.user_created')).toBeInTheDocument();
    expect(screen.getByText('当前管理员：admin')).toBeInTheDocument();
  });

  it('creates new users as annotators', async () => {
    apiMock.createAdminUser.mockResolvedValueOnce({
      id: 3,
      username: 'nurse',
      role: 'annotator',
      is_active: 1,
    });

    render(<UserAdmin />);
    await screen.findByText('doctor');
    fireEvent.change(screen.getByPlaceholderText('用户名'), { target: { value: 'nurse' } });
    fireEvent.change(screen.getByPlaceholderText('初始密码'), { target: { value: 'secret123' } });
    fireEvent.click(screen.getByRole('button', { name: /新增用户/ }));

    await waitFor(() => expect(apiMock.createAdminUser).toHaveBeenCalledWith({
      username: 'nurse',
      password: 'secret123',
      role: 'annotator',
      is_active: true,
    }));
    expect(await screen.findByText('用户已创建')).toBeInTheDocument();
  });

  it('updates status and password, and deletes users', async () => {
    apiMock.updateAdminUser.mockResolvedValueOnce({ id: 2, username: 'doctor', role: 'annotator', is_active: 0 });
    apiMock.updateAdminUser.mockResolvedValueOnce({ id: 2, username: 'doctor', role: 'annotator', is_active: 0 });
    apiMock.deleteAdminUser.mockResolvedValueOnce(undefined);

    render(<UserAdmin />);
    await screen.findByText('doctor');

    expect(screen.queryByText('观察员')).not.toBeInTheDocument();

    fireEvent.click(screen.getAllByRole('button', { name: '启用' })[1]);
    await waitFor(() => expect(apiMock.updateAdminUser).toHaveBeenCalledWith(2, { is_active: false }));

    fireEvent.click(screen.getAllByTitle('修改密码')[1]);
    fireEvent.change(screen.getByPlaceholderText('至少 6 位'), { target: { value: 'nextsecret' } });
    fireEvent.click(screen.getByRole('button', { name: '确认修改' }));
    await waitFor(() => expect(apiMock.updateAdminUser).toHaveBeenCalledWith(2, { password: 'nextsecret' }));

    fireEvent.click(screen.getAllByTitle('删除用户')[1]);
    fireEvent.click(screen.getByRole('button', { name: '确认删除' }));
    await waitFor(() => expect(apiMock.deleteAdminUser).toHaveBeenCalledWith(2));
  });

  it('requires two confirmations before resetting demo factory data', async () => {
    apiMock.resetDemoFactory.mockResolvedValueOnce({
      admin_user: { id: 1, username: 'admin', role: 'admin', is_active: 1 },
      project: {
        id: '8',
        name: '演示DICOM序列',
        status: 'ready',
        frames: 300,
        fps: '30FPS',
        source_type: 'dicom',
        video_path: 'uploads/8/dicom',
      },
      projects: [
        {
          id: '7',
          name: '演视LC视频序列',
          status: 'pending',
          frames: 0,
          fps: '30FPS',
          source_type: 'video',
          video_path: 'uploads/7/Data_MyVideo_1.mp4',
        },
        {
          id: '8',
          name: '演示DICOM序列',
          status: 'ready',
          frames: 300,
          fps: '30FPS',
          source_type: 'dicom',
          video_path: 'uploads/8/dicom',
        },
      ],
      deleted_counts: { users: 1 },
      message: '演示环境已恢复出厂设置',
    });
    apiMock.getAuditLogs.mockResolvedValueOnce([
      {
        id: 2,
        actor_user_id: 1,
        action: 'admin.demo_factory_reset',
        target_type: 'project',
        target_id: '8',
        detail: {},
        created_at: '2026-05-02T00:00:00Z',
      },
    ]);

    render(<UserAdmin />);
    await screen.findByText('doctor');
    fireEvent.click(screen.getByRole('button', { name: '恢复演示出厂设置' }));
    fireEvent.change(screen.getByLabelText('输入 RESET_DEMO_FACTORY 确认'), {
      target: { value: 'RESET_DEMO_FACTORY' },
    });
    fireEvent.click(screen.getByRole('button', { name: '确认恢复' }));

    await waitFor(() => expect(apiMock.resetDemoFactory).toHaveBeenCalledWith('RESET_DEMO_FACTORY'));
    expect(await screen.findByText('演示环境已恢复出厂设置')).toBeInTheDocument();
    expect(useStore.getState().projects).toEqual([
      expect.objectContaining({ name: '演视LC视频序列', source_type: 'video' }),
      expect.objectContaining({ name: '演示DICOM序列', source_type: 'dicom' }),
    ]);
    expect(useStore.getState().frames).toEqual([]);
    expect(useStore.getState().masks).toEqual([]);
  });

  it('does not reset demo data when confirmation text does not match', async () => {
    render(<UserAdmin />);
    await screen.findByText('doctor');
    fireEvent.click(screen.getByRole('button', { name: '恢复演示出厂设置' }));
    fireEvent.change(screen.getByLabelText('输入 RESET_DEMO_FACTORY 确认'), {
      target: { value: 'wrong' },
    });

    expect(apiMock.resetDemoFactory).not.toHaveBeenCalled();
    expect(screen.getByRole('button', { name: '确认恢复' })).toBeDisabled();
  });
});
