const { test, expect, request } = require('@playwright/test');
const { cleanDatabase, seedExistingUser, seedAdmin, disconnect, prisma } = require('./fixtures/database');

test.describe('管理员审核 + Hermes 同步流程', () => {
  let adminToken;
  let userToken;
  let roleId;

  test.beforeAll(async () => {
    await cleanDatabase();
    await seedExistingUser();
    await seedAdmin();

    // 管理员登录
    const adminContext = await request.newContext();
    const adminRes = await adminContext.post('/api/admin-auth/login', {
      data: { account: 'admin', password: 'admin123' },
    });
    const adminData = await adminRes.json();
    adminToken = adminData.token;

    // 用户登录
    const userContext = await request.newContext();
    const userRes = await userContext.post('/api/auth/login', {
      data: { account: 'e2e_existing', password: 'Test123456' },
    });
    const userData = await userRes.json();
    userToken = userData.token;

    // 创建角色（待审核）
    const roleRes = await userContext.post('/api/roles', {
      headers: { Authorization: `Bearer ${userToken}` },
      data: {
        displayName: '测试角色',
        personality: '温柔体贴',
        background: '来自未来',
        speechStyle: '轻声细语',
        greeting: '你好呀',
        soulMd: '# SOUL\n这是测试角色的灵魂文件',
      },
    });
    const roleData = await roleRes.json();
    roleId = roleData.role.id;
  });

  test.afterAll(async () => {
    await cleanDatabase();
    await disconnect();
  });

  test('管理员登录成功', async () => {
    expect(adminToken).toBeTruthy();
  });

  test('管理员登录密码错误返回 401', async () => {
    const context = await request.newContext();
    const res = await context.post('/api/admin-auth/login', {
      data: { account: 'admin', password: 'wrong' },
    });
    expect(res.status()).toBe(401);
  });

  test('用户 JWT 不能访问管理员接口', async () => {
    const context = await request.newContext();
    const res = await context.get('/api/admin/reviews', {
      headers: { Authorization: `Bearer ${userToken}` },
    });
    expect(res.status()).toBe(401);
  });

  test('无 token 不能访问管理员接口', async () => {
    const context = await request.newContext();
    const res = await context.get('/api/admin/reviews');
    expect(res.status()).toBe(401);
  });

  test('创建角色后状态为 pending_review', async () => {
    const role = await prisma.role.findUnique({ where: { id: roleId } });
    expect(role.reviewStatus).toBe('pending_review');
  });

  test('管理员获取待审核列表', async () => {
    const context = await request.newContext();
    const res = await context.get('/api/admin/reviews', {
      headers: { Authorization: `Bearer ${adminToken}` },
    });
    expect(res.status()).toBe(200);
    const data = await res.json();
    expect(data.roles.length).toBeGreaterThan(0);
    expect(data.roles[0].reviewStatus).toBe('pending_review');
  });

  test('管理员获取角色详情', async () => {
    const context = await request.newContext();
    const res = await context.get(`/api/admin/reviews/${roleId}`, {
      headers: { Authorization: `Bearer ${adminToken}` },
    });
    expect(res.status()).toBe(200);
    const data = await res.json();
    expect(data.role.displayName).toBe('测试角色');
  });

  test('管理员通过审核', async () => {
    const context = await request.newContext();
    const res = await context.post(`/api/admin/reviews/${roleId}/approve`, {
      headers: { Authorization: `Bearer ${adminToken}` },
    });
    expect(res.status()).toBe(200);
    const data = await res.json();
    expect(data.role.reviewStatus).toBe('approved');
  });

  test('角色库不显示未同步的角色', async () => {
    const context = await request.newContext();
    const res = await context.get('/api/roles');
    const data = await res.json();
    const found = data.roles.find((r) => r.id === roleId);
    expect(found).toBeUndefined();
  });

  test('对非 approved 角色发起同步返回 400', async () => {
    // 先创建一个新角色（pending_review）
    const userContext = await request.newContext();
    await userContext.post('/api/roles', {
      headers: { Authorization: `Bearer ${userToken}` },
      data: {
        displayName: '未审核角色',
        personality: '测试',
        background: '测试',
        speechStyle: '测试',
        greeting: '测试',
        soulMd: '# test',
      },
    });

    const roles = await prisma.role.findMany({ where: { displayName: '未审核角色' } });
    const pendingRoleId = roles[0].id;

    const adminContext = await request.newContext();
    const res = await adminContext.post(`/api/admin/sync/${pendingRoleId}`, {
      headers: { Authorization: `Bearer ${adminToken}` },
      data: { profileName: 'test-profile' },
    });
    expect(res.status()).toBe(400);
  });

  test('未配置 Hermes webhook URL 时同步返回 400', async () => {
    const context = await request.newContext();
    const res = await context.post(`/api/admin/sync/${roleId}`, {
      headers: { Authorization: `Bearer ${adminToken}` },
      data: { profileName: 'test-profile' },
    });
    expect(res.status()).toBe(400);
  });

  test('配置 Hermes webhook URL 指向 mock', async () => {
    const context = await request.newContext();
    const res = await context.put('/api/admin/config/HERMES_WEBHOOK_URL', {
      headers: { Authorization: `Bearer ${adminToken}` },
      data: { value: 'http://localhost:3001/api/mock-hermes/sync' },
    });
    expect(res.status()).toBe(200);
  });

  test('管理员发起同步 → mock Hermes 回调拉取文件 → 返回二维码', async () => {
    const context = await request.newContext();
    const res = await context.post(`/api/admin/sync/${roleId}`, {
      headers: { Authorization: `Bearer ${adminToken}` },
      data: {
        profileName: 'test-profile',
        modelKey: 'sk-test-key',
        provider: 'openrouter',
        multimediaModelKey: 'sk-multi-key',
        multimediaProvider: 'openrouter',
        enableSchedule: false,
      },
    });

    expect(res.status()).toBe(200);
    const data = await res.json();
    expect(data.role.reviewStatus).toBe('synced');
    expect(data.role.qrCodeUrl).toContain('mock.hermes.local');
    expect(data.profileId).toContain('mock-profile');
  });

  test('同步成功后角色出现在角色库', async () => {
    const context = await request.newContext();
    const res = await context.get('/api/roles');
    const data = await res.json();
    const found = data.roles.find((r) => r.id === roleId);
    expect(found).toBeDefined();
  });

  test('用户查看自己的角色列表包含审核状态和二维码', async () => {
    const context = await request.newContext();
    const res = await context.get('/api/roles/my/roles', {
      headers: { Authorization: `Bearer ${userToken}` },
    });
    const data = await res.json();
    const role = data.roles.find((r) => r.id === roleId);
    expect(role).toBeDefined();
    expect(role.reviewStatus).toBe('synced');
    expect(role.qrCodeUrl).toBeTruthy();
  });

  test('sync_token 拉取文件 — SOUL.md', async () => {
    // 生成新的 sync_token（通过管理员发起同步流程会自动生成）
    // 这里直接用 API 测试：先通过审核另一个角色，再同步
    const userContext = await request.newContext();

    // 创建并审核新角色
    const roleRes = await userContext.post('/api/roles', {
      headers: { Authorization: `Bearer ${userToken}` },
      data: {
        displayName: '同步测试角色',
        personality: '测试',
        background: '测试',
        speechStyle: '测试',
        greeting: '测试',
        soulMd: '# Test SOUL\n测试内容',
      },
    });
    const newRoleId = (await roleRes.json()).role.id;

    // 管理员审核通过
    const adminContext = await request.newContext();
    await adminContext.post(`/api/admin/reviews/${newRoleId}/approve`, {
      headers: { Authorization: `Bearer ${adminToken}` },
    });

    // 发起同步（mock Hermes 会回调拉取文件）
    const syncRes = await adminContext.post(`/api/admin/sync/${newRoleId}`, {
      headers: { Authorization: `Bearer ${adminToken}` },
      data: {
        profileName: 'test-profile-2',
        modelKey: 'sk-test',
        provider: 'openrouter',
      },
    });

    expect(syncRes.status()).toBe(200);
    const syncData = await syncRes.json();
    expect(syncData.role.reviewStatus).toBe('synced');
  });

  test('驳回审核流程', async () => {
    const userContext = await request.newContext();
    const roleRes = await userContext.post('/api/roles', {
      headers: { Authorization: `Bearer ${userToken}` },
      data: {
        displayName: '待驳回角色',
        personality: '测试',
        background: '测试',
        speechStyle: '测试',
        greeting: '测试',
        soulMd: '# test',
      },
    });
    const rejectRoleId = (await roleRes.json()).role.id;

    const adminContext = await request.newContext();
    const res = await adminContext.post(`/api/admin/reviews/${rejectRoleId}/reject`, {
      headers: { Authorization: `Bearer ${adminToken}` },
      data: { reviewNote: '内容不符合要求' },
    });

    expect(res.status()).toBe(200);
    const data = await res.json();
    expect(data.role.reviewStatus).toBe('rejected');
    expect(data.role.reviewNote).toBe('内容不符合要求');
  });

  test('向后兼容：API Key 拉取仍正常工作', async () => {
    // 生成 API Key
    const userContext = await request.newContext();
    const keyRes = await userContext.post('/api/apikeys', {
      headers: { Authorization: `Bearer ${userToken}` },
      data: { name: 'test-key' },
    });
    const apiKey = (await keyRes.json()).apiKey.key;

    // 用 API Key 拉取 SOUL.md
    const soulRes = await userContext.get(`/api/hermes/roles/${roleId}/SOUL.md`, {
      headers: { Authorization: `Bearer ${apiKey}` },
    });
    expect(soulRes.status()).toBe(200);
    const soulText = await soulRes.text();
    expect(soulText).toContain('测试角色的灵魂文件');
  });

  test('管理员获取同步状态列表', async () => {
    const context = await request.newContext();
    const res = await context.get('/api/admin/sync-status', {
      headers: { Authorization: `Bearer ${adminToken}` },
    });
    expect(res.status()).toBe(200);
    const data = await res.json();
    expect(data.roles.length).toBeGreaterThan(0);
    expect(data.roles.some((r) => r.reviewStatus === 'synced')).toBe(true);
  });
});
