// 集成测试：EternalAI → hermes-server 端到端同步流程
// 前提：EternalAI (3001) 和 hermes-server (3002) 均已运行，SYNC_SECRET 已同步
// 前提：hermes-server 的 .env 已配置 ETERNALALAI_BASE_URL=http://localhost:3001

const BASE_ETERNAL = 'http://localhost:3001';
const BASE_HERMES = 'http://localhost:3002';
const HERMES_ADMIN_TOKEN = 'dev_only_admin_token_change_me';

let passed = 0;
let failed = 0;

async function assert(name, fn) {
  try {
    await fn();
    passed++;
    console.log(`  ✓ ${name}`);
  } catch (err) {
    failed++;
    console.log(`  ✗ ${name}`);
    console.log(`    ${err.message}`);
  }
}

function assertEqual(actual, expected, msg) {
  if (actual !== expected) {
    throw new Error(`${msg || ''} expected ${JSON.stringify(expected)}, got ${JSON.stringify(actual)}`);
  }
}

function assertTruthy(val, msg) {
  if (!val) throw new Error(msg || 'expected truthy value');
}

// 清理 hermes-server 上的所有 profile（避免重复运行导致冲突）
async function cleanupHermesProfiles() {
  try {
    const res = await fetch(`${BASE_HERMES}/api/profiles`, {
      headers: { Authorization: `Bearer ${HERMES_ADMIN_TOKEN}` },
    });
    if (!res.ok) return;
    const data = await res.json();
    for (const p of data.profiles || []) {
      try {
        await fetch(`${BASE_HERMES}/api/profiles/${p.profileId}`, {
          method: 'DELETE',
          headers: { Authorization: `Bearer ${HERMES_ADMIN_TOKEN}` },
        });
      } catch {}
    }
    console.log(`  已清理 hermes-server 上 ${data.profiles?.length || 0} 个 profile`);
  } catch (err) {
    console.log(`  清理 hermes-server 跳过: ${err.message}`);
  }
}

async function main() {
  const prisma = require('../../src/lib/prisma');
  const { hashPassword } = require('../../src/lib/auth');

  // ===== 清理数据库 =====
  console.log('\n===== 准备：清理数据库 =====');
  await prisma.order.deleteMany();
  await prisma.apiKey.deleteMany();
  await prisma.role.deleteMany();
  await prisma.admin.deleteMany();
  await prisma.user.deleteMany();
  await prisma.systemConfig.deleteMany({ where: { key: 'HERMES_WEBHOOK_URL' } });

  // 确保 SYNC_SECRET 存在
  const crypto = require('crypto');
  await prisma.systemConfig.upsert({
    where: { key: 'SYNC_SECRET' },
    update: {},
    create: { key: 'SYNC_SECRET', value: crypto.randomBytes(32).toString('hex') },
  });

  // P1 修复：清理 hermes-server 上的残留 profile（避免重复运行测试失败）
  console.log('\n===== 准备：清理 hermes-server 数据 =====');
  await cleanupHermesProfiles();

  // 创建测试用户和管理员
  const user = await prisma.user.create({
    data: { account: 'itest_user', password: hashPassword('Test123456'), isCreator: true },
  });
  const admin = await prisma.admin.create({
    data: { account: 'itest_admin', password: hashPassword('admin123') },
  });
  console.log(`  用户: ${user.id}, 管理员: ${admin.id}`);

  // ===== 测试开始 =====
  console.log('\n===== 测试：EternalAI → hermes-server 集成 =====');

  let adminToken, userToken, roleId;

  // 1. 管理员登录
  await assert('管理员登录', async () => {
    const res = await fetch(`${BASE_ETERNAL}/api/admin-auth/login`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ account: 'itest_admin', password: 'admin123' }),
    });
    assertEqual(res.status, 200, '管理员登录状态码');
    const data = await res.json();
    assertTruthy(data.token, '管理员 token');
    adminToken = data.token;
  });

  // 2. 用户登录
  await assert('用户登录', async () => {
    const res = await fetch(`${BASE_ETERNAL}/api/auth/login`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ account: 'itest_user', password: 'Test123456' }),
    });
    assertEqual(res.status, 200, '用户登录状态码');
    const data = await res.json();
    assertTruthy(data.token, '用户 token');
    userToken = data.token;
  });

  // 3. 用户创建角色
  await assert('用户创建角色', async () => {
    const res = await fetch(`${BASE_ETERNAL}/api/roles`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${userToken}` },
      body: JSON.stringify({
        displayName: '集成测试角色',
        personality: '温柔善良',
        background: '来自星辰大海',
        speechStyle: '轻声细语',
        greeting: '你好呀，我是星灵',
        soulMd: '# SOUL\n\n我是星灵，来自星辰大海的守护者。\n我温柔善良，喜欢倾听你的故事。',
      }),
    });
    assertEqual(res.status, 200, '创建角色状态码');
    const data = await res.json();
    assertTruthy(data.role.id, '角色 ID');
    assertEqual(data.role.reviewStatus, 'pending_review', '初始审核状态');
    roleId = data.role.id;
  });

  // 4. 管理员审核通过
  await assert('管理员审核通过', async () => {
    const res = await fetch(`${BASE_ETERNAL}/api/admin/reviews/${roleId}/approve`, {
      method: 'POST',
      headers: { Authorization: `Bearer ${adminToken}` },
    });
    assertEqual(res.status, 200, '审核状态码');
    const data = await res.json();
    assertEqual(data.role.reviewStatus, 'approved', '审核后状态');
  });

  // 5. 配置 Hermes webhook URL 指向真实 hermes-server
  await assert('配置 HERMES_WEBHOOK_URL 指向 hermes-server', async () => {
    const res = await fetch(`${BASE_ETERNAL}/api/admin/config/HERMES_WEBHOOK_URL`, {
      method: 'PUT',
      headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${adminToken}` },
      body: JSON.stringify({ value: `${BASE_HERMES}/api/sync` }),
    });
    assertEqual(res.status, 200, '配置状态码');
  });

  // 6. 管理员发起同步 → hermes-server 接收 → 回调拉取文件 → 创建 profile → 返回二维码
  let syncResponse;
  await assert('管理员发起同步（真实 hermes-server）', async () => {
    const res = await fetch(`${BASE_ETERNAL}/api/admin/sync/${roleId}`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${adminToken}` },
      body: JSON.stringify({
        profileName: 'star-spirit',
        modelKey: 'sk-test-key',
        provider: 'openrouter',
        multimediaModelKey: 'sk-multi-key',
        multimediaProvider: 'openrouter',
        enableSchedule: false,
      }),
    });
    assertEqual(res.status, 200, '同步状态码');
    const data = await res.json();
    assertEqual(data.role.reviewStatus, 'synced', '同步后状态');
    assertTruthy(data.role.qrCodeUrl, '二维码 URL');
    assertTruthy(data.profileId, 'profileId');
    assertTruthy(data.profileId.startsWith('hermes_'), 'profileId 前缀');
    syncResponse = data;
    console.log(`    profileId: ${data.profileId}`);
    console.log(`    qrCodeUrl: ${data.role.qrCodeUrl}`);
  });

  // 7. 验证 hermes-server 健康检查
  await assert('hermes-server 健康检查', async () => {
    const res = await fetch(`${BASE_HERMES}/api/health`);
    assertEqual(res.status, 200, '健康检查状态码');
    const data = await res.json();
    assertEqual(data.status, 'ok', '健康状态');
    // P2 修复后：health 不再泄露 syncSecretConfigured，改用 storageOk/status
    assertEqual(data.profileCount, 1, 'profile 数量');
  });

  // 8. 验证 hermes-server profile 列表
  await assert('hermes-server profile 列表', async () => {
    const res = await fetch(`${BASE_HERMES}/api/profiles`, {
      headers: { Authorization: `Bearer ${HERMES_ADMIN_TOKEN}` },
    });
    assertEqual(res.status, 200, 'profile 列表状态码');
    const data = await res.json();
    assertEqual(data.total, 1, 'profile 总数');
    assertEqual(data.profiles[0].profileName, 'star-spirit', 'profile 名称');
    assertEqual(data.profiles[0].roleId, roleId, 'roleId 关联');
    // P0 修复后：sourceBaseUrl 来自 hermes-server 的 ETERNALAI_BASE_URL 环境变量
    assertEqual(data.profiles[0].sourceBaseUrl, BASE_ETERNAL, 'sourceBaseUrl 来自环境变量');
  });

  // 9. 验证 hermes-server profile 详情
  await assert('hermes-server profile 详情', async () => {
    const res = await fetch(`${BASE_HERMES}/api/profiles/${syncResponse.profileId}`, {
      headers: { Authorization: `Bearer ${HERMES_ADMIN_TOKEN}` },
    });
    assertEqual(res.status, 200, 'profile 详情状态码');
    const data = await res.json();
    assertEqual(data.profile.profileId, syncResponse.profileId, 'profileId');
    assertEqual(data.profile.modelKey, 'sk-test-key', 'modelKey');
    assertEqual(data.profile.provider, 'openrouter', 'provider');
    assertEqual(data.profile.enableSchedule, false, 'enableSchedule');
    assertEqual(data.profile.boundWechat, null, '未绑定状态');
  });

  // 10. 验证 hermes-server 提供 SOUL.md 下载
  await assert('hermes-server 提供 SOUL.md 下载', async () => {
    const res = await fetch(`${BASE_HERMES}/api/profiles/${syncResponse.profileId}/SOUL.md`);
    assertEqual(res.status, 200, 'SOUL.md 状态码');
    const text = await res.text();
    assertTruthy(text.includes('星灵'), 'SOUL.md 内容包含角色名');
    assertTruthy(text.includes('星辰大海'), 'SOUL.md 内容包含背景');
  });

  // 11. 验证 hermes-server 提供 config.yaml 下载
  await assert('hermes-server 提供 config.yaml 下载', async () => {
    const res = await fetch(`${BASE_HERMES}/api/profiles/${syncResponse.profileId}/config.yaml`);
    assertEqual(res.status, 200, 'config.yaml 状态码');
    const text = await res.text();
    assertTruthy(text.includes('model:'), 'config.yaml 包含 model 字段');
    assertTruthy(text.includes('temperature:'), 'config.yaml 包含 temperature 字段');
  });

  // 12. 验证二维码图片可访问
  await assert('二维码图片可访问', async () => {
    const res = await fetch(syncResponse.role.qrCodeUrl);
    assertEqual(res.status, 200, '二维码图片状态码');
    assertEqual(res.headers.get('content-type'), 'image/png', '二维码图片类型');
    const buffer = await res.arrayBuffer();
    assertTruthy(buffer.byteLength > 100, '二维码图片大小');
  });

  // 13. 验证绑定页面可访问
  await assert('绑定页面可访问', async () => {
    const res = await fetch(`${BASE_HERMES}/api/bind/${syncResponse.profileId}`);
    assertEqual(res.status, 200, '绑定页面状态码');
    const html = await res.text();
    assertTruthy(html.includes('star-spirit'), '绑定页面包含 profile 名称');
    assertTruthy(html.includes('确认绑定'), '绑定页面包含绑定按钮');
  });

  // 14. 执行绑定
  await assert('执行绑定', async () => {
    const res = await fetch(`${BASE_HERMES}/api/bind/${syncResponse.profileId}`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ wechatId: 'wx_test_12345' }),
    });
    assertEqual(res.status, 200, '绑定状态码');
    const data = await res.json();
    assertEqual(data.profileId, syncResponse.profileId, '绑定返回 profileId');
    assertTruthy(data.boundAt, '绑定时间');
  });

  // 15. 验证已绑定后再次绑定返回 400
  await assert('重复绑定返回 400', async () => {
    const res = await fetch(`${BASE_HERMES}/api/bind/${syncResponse.profileId}`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ wechatId: 'wx_other' }),
    });
    assertEqual(res.status, 400, '重复绑定状态码');
  });

  // 16. 验证已绑定页面显示
  await assert('已绑定页面显示', async () => {
    const res = await fetch(`${BASE_HERMES}/api/bind/${syncResponse.profileId}`);
    const html = await res.text();
    assertTruthy(html.includes('已成功绑定'), '已绑定页面提示');
  });

  // 17. 验证 EternalAI 角色库显示已同步角色
  await assert('EternalAI 角色库显示已同步角色', async () => {
    const res = await fetch(`${BASE_ETERNAL}/api/roles`);
    const data = await res.json();
    const found = data.roles.find((r) => r.id === roleId);
    assertTruthy(found, '角色库包含已同步角色');
  });

  // 18. 验证 SYNC_SECRET 写保护（不能通过 PUT 修改）
  await assert('SYNC_SECRET 写保护', async () => {
    const res = await fetch(`${BASE_ETERNAL}/api/admin/config/SYNC_SECRET`, {
      method: 'PUT',
      headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${adminToken}` },
      body: JSON.stringify({ value: 'hacked' }),
    });
    assertEqual(res.status, 403, '写保护状态码');
  });

  // 19. 验证无效 sync_token 被拒绝
  await assert('无效 sync_token 被拒绝', async () => {
    const res = await fetch(`${BASE_HERMES}/api/sync`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        profileName: 'test',
        syncToken: 'invalid.token.here',
        roleId: 'fake-id',
      }),
    });
    assertEqual(res.status, 401, '无效 token 状态码');
  });

  // 20. 验证缺少参数被拒绝
  await assert('缺少参数被拒绝', async () => {
    const res = await fetch(`${BASE_HERMES}/api/sync`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ profileName: 'test' }),
    });
    assertEqual(res.status, 400, '缺少参数状态码');
  });

  // ===== 清理 =====
  console.log('\n===== 清理 =====');
  // 清理 hermes-server 上的 profile
  await cleanupHermesProfiles();
  // 清理 EternalAI 数据库
  await prisma.order.deleteMany();
  await prisma.apiKey.deleteMany();
  await prisma.role.deleteMany();
  await prisma.admin.deleteMany();
  await prisma.user.deleteMany();
  await prisma.systemConfig.deleteMany({ where: { key: 'HERMES_WEBHOOK_URL' } });
  await prisma.$disconnect();

  // ===== 结果 =====
  console.log(`\n===== 结果: ${passed} passed, ${failed} failed =====`);
  process.exit(failed > 0 ? 1 : 0);
}

main().catch((err) => {
  console.error('测试运行失败:', err);
  process.exit(1);
});
