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

const hostApiFetchMock = vi.fn();
const toastSuccessMock = vi.fn();
const toastErrorMock = vi.fn();

vi.mock('@/lib/host-api', () => ({
  hostApiFetch: (...args: unknown[]) => hostApiFetchMock(...args),
}));

vi.mock('sonner', () => ({
  toast: {
    success: (...args: unknown[]) => toastSuccessMock(...args),
    error: (...args: unknown[]) => toastErrorMock(...args),
  },
}));

type TestDocumentKind = 'soul' | 'identity' | 'user' | 'agent' | 'tool' | 'heartbeat' | 'boot';

function makeSnapshot(agentId = 'main', overrides?: Partial<Record<TestDocumentKind, string>>) {
  const documents = [
    {
      kind: 'soul',
      fileName: 'SOUL.md',
      path: `/tmp/${agentId}/SOUL.md`,
      exists: true,
      source: 'workspace',
      content: overrides?.soul ?? '# Soul\n',
      size: 7,
      updatedAt: 1,
      templateAvailable: true,
      templatePath: '/runtime/SOUL.md',
    },
    {
      kind: 'identity',
      fileName: 'IDENTITY.md',
      path: `/tmp/${agentId}/IDENTITY.md`,
      exists: true,
      source: 'workspace',
      content: overrides?.identity ?? '# Identity\n',
      size: 11,
      updatedAt: 1,
      templateAvailable: true,
      templatePath: '/runtime/IDENTITY.md',
    },
    {
      kind: 'user',
      fileName: 'USER.md',
      path: `/tmp/${agentId}/USER.md`,
      exists: true,
      source: 'workspace',
      content: overrides?.user ?? '# User\n',
      size: 7,
      updatedAt: 1,
      templateAvailable: true,
      templatePath: '/runtime/USER.md',
    },
    {
      kind: 'agent',
      fileName: 'AGENTS.md',
      path: `/tmp/${agentId}/AGENTS.md`,
      exists: true,
      source: 'workspace',
      content: overrides?.agent ?? '# Agent\n',
      size: 8,
      updatedAt: 1,
      templateAvailable: true,
      templatePath: '/runtime/AGENTS.md',
    },
    {
      kind: 'tool',
      fileName: 'TOOLS.md',
      path: `/tmp/${agentId}/TOOLS.md`,
      exists: false,
      source: 'template',
      content: overrides?.tool ?? '# Tool\n',
      size: 0,
      updatedAt: null,
      templateAvailable: true,
      templatePath: '/runtime/TOOLS.md',
    },
    {
      kind: 'heartbeat',
      fileName: 'HEARTBEAT.md',
      path: `/tmp/${agentId}/HEARTBEAT.md`,
      exists: false,
      source: 'template',
      content: overrides?.heartbeat ?? '# Heartbeat\n',
      size: 0,
      updatedAt: null,
      templateAvailable: true,
      templatePath: '/runtime/HEARTBEAT.md',
    },
    {
      kind: 'boot',
      fileName: 'BOOT.md',
      path: `/tmp/${agentId}/BOOT.md`,
      exists: false,
      source: 'template',
      content: overrides?.boot ?? '# Boot\n',
      size: 0,
      updatedAt: null,
      templateAvailable: true,
      templatePath: '/runtime/BOOT.md',
    },
  ];

  return {
    success: true,
    selectedAgentId: agentId,
    defaultAgentId: 'main',
    agents: [
      { id: 'main', name: 'Main', isDefault: true, workspace: '~/.openclaw/workspace' },
      { id: 'coder', name: 'Coder', isDefault: false, workspace: '~/.openclaw/workspace-coder' },
    ],
    documents,
    paths: {
      workspace: `/tmp/${agentId}`,
      templateDir: '/runtime',
    },
  };
}

describe('AgentSystemDocumentsSettings', () => {
  beforeEach(async () => {
    vi.clearAllMocks();
    await i18n.changeLanguage('zh');
    hostApiFetchMock.mockImplementation((path: string, init?: { method?: string; body?: string }) => {
      if (path === '/api/agent-system-documents?agentId=coder') {
        return Promise.resolve(makeSnapshot('coder', { soul: '# Coder soul\n' }));
      }
      if (path === '/api/agent-system-documents/soul' && init?.method === 'PUT') {
        const body = JSON.parse(init.body || '{}') as { content?: string };
        return Promise.resolve(makeSnapshot('main', { soul: body.content ?? '' }));
      }
      if (path === '/api/agent-system-documents/tool/reset' && init?.method === 'POST') {
        return Promise.resolve(makeSnapshot('main', { tool: '# Tool template\n' }));
      }
      return Promise.resolve(makeSnapshot('main'));
    });
  });

  it('loads system documents and switches selected agent', async () => {
    render(<AgentSystemDocumentsSettings />);

    expect(await screen.findByTestId('agent-system-document-editor')).toHaveValue('# Soul\n');
    expect(screen.getByTestId('agent-system-document-tab-soul')).toHaveTextContent('SOUL.md');

    fireEvent.change(screen.getByTestId('agent-system-document-agent-select'), {
      target: { value: 'coder' },
    });

    await waitFor(() => {
      expect(hostApiFetchMock).toHaveBeenCalledWith('/api/agent-system-documents?agentId=coder');
    });
    expect(await screen.findByTestId('agent-system-document-editor')).toHaveValue('# Coder soul\n');
  });

  it('saves the edited selected document', async () => {
    render(<AgentSystemDocumentsSettings />);

    const editor = await screen.findByTestId('agent-system-document-editor');
    fireEvent.change(editor, { target: { value: '# Updated soul\n' } });
    fireEvent.click(screen.getByTestId('agent-system-document-save'));

    await waitFor(() => {
      expect(hostApiFetchMock).toHaveBeenCalledWith(
        '/api/agent-system-documents/soul',
        expect.objectContaining({
          method: 'PUT',
          body: JSON.stringify({ agentId: 'main', content: '# Updated soul\n' }),
        }),
      );
    });
    expect(toastSuccessMock).toHaveBeenCalledWith('SOUL.md 已保存');
  });

  it('restores the selected tool document from template', async () => {
    render(<AgentSystemDocumentsSettings />);

    await screen.findByTestId('agent-system-document-editor');
    fireEvent.click(screen.getByTestId('agent-system-document-tab-tool'));
    fireEvent.click(screen.getByTestId('agent-system-document-reset'));

    await waitFor(() => {
      expect(hostApiFetchMock).toHaveBeenCalledWith(
        '/api/agent-system-documents/tool/reset',
        expect.objectContaining({
          method: 'POST',
          body: JSON.stringify({ agentId: 'main' }),
        }),
      );
    });
    expect(await screen.findByTestId('agent-system-document-editor')).toHaveValue('# Tool template\n');
  });

  it('shows the OpenClaw workspace control documents', async () => {
    render(<AgentSystemDocumentsSettings />);

    await screen.findByTestId('agent-system-document-editor');

    expect(screen.getByTestId('agent-system-document-tab-identity')).toHaveTextContent('IDENTITY.md');
    expect(screen.getByTestId('agent-system-document-tab-user')).toHaveTextContent('USER.md');
    expect(screen.getByTestId('agent-system-document-tab-heartbeat')).toHaveTextContent('HEARTBEAT.md');
    expect(screen.getByTestId('agent-system-document-tab-boot')).toHaveTextContent('BOOT.md');
  });

});
