/**
 * FFAI Agent — mcp-admin API 集成测试（Phase 2）
 *
 * 覆盖：
 *   - GET /admin/mcp/servers list（同 org 过滤）
 *   - POST /admin/mcp/servers create（必填字段 + transport 枚举校验）
 *   - DELETE /admin/mcp/servers/:id 删除（跨 org 拒绝）
 *   - GET /admin/mcp/status connection 健康
 *   - JWT 缺失 401
 *
 * NOTE：测试环境 FFAI_MCP_ENABLED 默认 false → create 不真 spawn 子进程，
 *       只测 controller + service + Prisma 持久化层（不依赖外部 MCP server）。
 */
import { INestApplication } from '@nestjs/common';
import request from 'supertest';
import { PrismaService } from '@/core/database/prisma/prisma.service';
import { cleanupDatabase } from '../../helpers/cleanup.helper';
import { createTestApp } from '../../helpers/app.helper';
import { setupIntegrationTest } from '../../helpers/test-setup.helper';

describe('FFAI Agent - MCP Admin API (Phase 2)', () => {
  let app: INestApplication;
  let prisma: PrismaService;
  let adminToken: string;
  let orgId: string;

  beforeAll(async () => {
    app = await createTestApp();
    prisma = app.get<PrismaService>(PrismaService);
  });

  beforeEach(async () => {
    const ctx = await setupIntegrationTest(app, prisma);
    adminToken = ctx.adminToken;
    const org = await prisma.organization.findFirst({ orderBy: { createdAt: 'asc' } });
    orgId = org!.id;
  });

  afterEach(async () => {
    await cleanupDatabase(prisma);
  });

  afterAll(async () => {
    await app.close();
  });

  it('[AGENT-MCP-001] POST /admin/mcp/servers 创建 stdio server', async () => {
    const res = await request(app.getHttpServer())
      .post('/api/v1/agent/admin/mcp/servers')
      .set('Authorization', `Bearer ${adminToken}`)
      .set('X-Organization-Id', orgId)
      .send({
        name: 'Test Filesystem MCP',
        transport: 'stdio',
        endpoint: '/usr/bin/echo',
        args: ['--mcp'],
      })
      .expect(201);

    expect(res.body.data.name).toBe('Test Filesystem MCP');
    expect(res.body.data.transport).toBe('stdio');
    expect(res.body.data.endpoint).toBe('/usr/bin/echo');
    expect(res.body.data.enabled).toBe(true);
    expect(res.body.data.organizationId).toBe(orgId);
    // args 是 JSON string 序列化
    expect(JSON.parse(res.body.data.args ?? '[]')).toEqual(['--mcp']);
  });

  it('[AGENT-MCP-002] POST 校验：name required + 非法 transport + 空 endpoint → 400', async () => {
    await request(app.getHttpServer())
      .post('/api/v1/agent/admin/mcp/servers')
      .set('Authorization', `Bearer ${adminToken}`)
      .set('X-Organization-Id', orgId)
      .send({ name: '', transport: 'stdio', endpoint: '/x' })
      .expect(400);
    await request(app.getHttpServer())
      .post('/api/v1/agent/admin/mcp/servers')
      .set('Authorization', `Bearer ${adminToken}`)
      .set('X-Organization-Id', orgId)
      .send({ name: 'ok', transport: 'foo', endpoint: '/x' })
      .expect(400);
    await request(app.getHttpServer())
      .post('/api/v1/agent/admin/mcp/servers')
      .set('Authorization', `Bearer ${adminToken}`)
      .set('X-Organization-Id', orgId)
      .send({ name: 'ok', transport: 'stdio', endpoint: '' })
      .expect(400);
  });

  it('[AGENT-MCP-003] GET /admin/mcp/servers 只列同 org 的 server', async () => {
    const otherOrg = await prisma.organization.create({
      data: { code: `T_MCP_${Date.now()}`, name: 'other-org-mcp' },
    });
    await prisma.agentMcpServer.create({
      data: {
        organizationId: otherOrg.id,
        createdById: '00000000-0000-0000-0000-000000000000',
        name: 'foreign-server',
        transport: 'stdio',
        endpoint: '/x',
      },
    });
    await request(app.getHttpServer())
      .post('/api/v1/agent/admin/mcp/servers')
      .set('Authorization', `Bearer ${adminToken}`)
      .set('X-Organization-Id', orgId)
      .send({ name: 'my-server', transport: 'stdio', endpoint: '/y' });

    const res = await request(app.getHttpServer())
      .get('/api/v1/agent/admin/mcp/servers')
      .set('Authorization', `Bearer ${adminToken}`)
      .set('X-Organization-Id', orgId)
      .expect(200);
    const names = (res.body.data.items as Array<{ name: string }>).map((s) => s.name);
    expect(names).toContain('my-server');
    expect(names).not.toContain('foreign-server');
  });

  it('[AGENT-MCP-004] DELETE /admin/mcp/servers/:id 跨 org → 403', async () => {
    const otherOrg = await prisma.organization.create({
      data: { code: `T_MCP2_${Date.now()}`, name: 'other-org-mcp2' },
    });
    const s = await prisma.agentMcpServer.create({
      data: {
        organizationId: otherOrg.id,
        createdById: '00000000-0000-0000-0000-000000000000',
        name: 'cross-org-server',
        transport: 'stdio',
        endpoint: '/z',
      },
    });
    await request(app.getHttpServer())
      .delete(`/api/v1/agent/admin/mcp/servers/${s.id}`)
      .set('Authorization', `Bearer ${adminToken}`)
      .set('X-Organization-Id', orgId)
      .expect(403);
  });

  it('[AGENT-MCP-005] DELETE 同 org 删除成功', async () => {
    const created = await request(app.getHttpServer())
      .post('/api/v1/agent/admin/mcp/servers')
      .set('Authorization', `Bearer ${adminToken}`)
      .set('X-Organization-Id', orgId)
      .send({ name: 'to-delete', transport: 'stdio', endpoint: '/x' });
    await request(app.getHttpServer())
      .delete(`/api/v1/agent/admin/mcp/servers/${created.body.data.id}`)
      .set('Authorization', `Bearer ${adminToken}`)
      .set('X-Organization-Id', orgId)
      .expect(200);
    const row = await prisma.agentMcpServer.findUnique({ where: { id: created.body.data.id } });
    expect(row).toBeNull();
  });

  it('[AGENT-MCP-006] GET /admin/mcp/status 返 connections 数组（FFAI_MCP_ENABLED=false 时空数组）', async () => {
    const res = await request(app.getHttpServer())
      .get('/api/v1/agent/admin/mcp/status')
      .set('Authorization', `Bearer ${adminToken}`)
      .set('X-Organization-Id', orgId)
      .expect(200);
    expect(Array.isArray(res.body.data.connections)).toBe(true);
  });

  it('[AGENT-MCP-007] 无 JWT → 401', async () => {
    await request(app.getHttpServer())
      .get('/api/v1/agent/admin/mcp/servers')
      .set('X-Organization-Id', orgId)
      .expect(401);
  });

  it('[AGENT-MCP-008] list 出口对 env / args 做 redaction（避免 admin 互窃凭据）', async () => {
    await request(app.getHttpServer())
      .post('/api/v1/agent/admin/mcp/servers')
      .set('Authorization', `Bearer ${adminToken}`)
      .set('X-Organization-Id', orgId)
      .send({
        name: 'secret-server',
        transport: 'stdio',
        endpoint: '/usr/bin/cat',
        args: ['--token=PLAINTEXT_SECRET'],
        env: { GITHUB_TOKEN: 'ghp_REAL_SECRET', NOTION_KEY: 'secret_xx' },
      });

    const res = await request(app.getHttpServer())
      .get('/api/v1/agent/admin/mcp/servers')
      .set('Authorization', `Bearer ${adminToken}`)
      .set('X-Organization-Id', orgId)
      .expect(200);

    const target = (res.body.data.items as Array<{
      name: string;
      env: string | null;
      args: string | null;
    }>).find((s) => s.name === 'secret-server');
    expect(target).toBeDefined();
    expect(target!.env).toBe('[REDACTED]');
    expect(target!.args).toBe('[REDACTED]');
    // 禁止真凭据泄漏到 list response 任何位置
    expect(JSON.stringify(res.body)).not.toContain('ghp_REAL_SECRET');
    expect(JSON.stringify(res.body)).not.toContain('PLAINTEXT_SECRET');
  });
});
