/**
 * 管理员功能完整性测试脚本（Cookie + CSRF 认证模型）
 *
 * 覆盖范围：
 * 1. 鉴权与权限校验
 * 2. 用户管理（列表、封禁/删除自保护、存储权限）
 * 3. 系统设置（获取/更新/参数校验）
 * 4. 分享管理
 * 5. 系统监控（健康、存储、日志）
 * 6. 上传工具接口
 */

const http = require('http');
const https = require('https');
const { UserDB } = require('./database');

const BASE_URL = process.env.TEST_BASE_URL || 'http://127.0.0.1:40001';

const state = {
  adminSession: {
    cookies: {},
    csrfToken: ''
  },
  adminUserId: null,
  testUserId: null,
  latestSettings: null
};

const testResults = {
  passed: [],
  failed: [],
  warnings: []
};

function makeCookieHeader(cookies) {
  return Object.entries(cookies || {})
    .map(([k, v]) => `${k}=${v}`)
    .join('; ');
}

function storeSetCookies(session, setCookieHeader) {
  if (!session || !setCookieHeader) return;
  const list = Array.isArray(setCookieHeader) ? setCookieHeader : [setCookieHeader];
  for (const raw of list) {
    const first = String(raw || '').split(';')[0];
    const idx = first.indexOf('=');
    if (idx <= 0) continue;
    const key = first.slice(0, idx).trim();
    const value = first.slice(idx + 1).trim();
    session.cookies[key] = value;
    if (key === 'csrf_token') {
      session.csrfToken = value;
    }
  }
}

function isSafeMethod(method) {
  const upper = String(method || '').toUpperCase();
  return upper === 'GET' || upper === 'HEAD' || upper === 'OPTIONS';
}

function request(method, path, options = {}) {
  const {
    data = null,
    session = null,
    headers = {},
    requireCsrf = true
  } = options;

  return new Promise((resolve, reject) => {
    const url = new URL(path, BASE_URL);
    const transport = url.protocol === 'https:' ? https : http;

    const requestHeaders = { ...headers };
    if (session) {
      const cookieHeader = makeCookieHeader(session.cookies);
      if (cookieHeader) {
        requestHeaders.Cookie = cookieHeader;
      }

      if (requireCsrf && !isSafeMethod(method)) {
        const csrfToken = session.csrfToken || session.cookies.csrf_token;
        if (csrfToken) {
          requestHeaders['X-CSRF-Token'] = csrfToken;
        }
      }
    }

    let payload = null;
    if (data !== null && data !== undefined) {
      payload = JSON.stringify(data);
      requestHeaders['Content-Type'] = 'application/json';
      requestHeaders['Content-Length'] = Buffer.byteLength(payload);
    }

    const req = transport.request({
      protocol: url.protocol,
      hostname: url.hostname,
      port: url.port || (url.protocol === 'https:' ? 443 : 80),
      path: url.pathname + url.search,
      method,
      headers: requestHeaders
    }, (res) => {
      let body = '';
      res.on('data', chunk => {
        body += chunk;
      });
      res.on('end', () => {
        if (session) {
          storeSetCookies(session, res.headers['set-cookie']);
        }

        let parsed = body;
        try {
          parsed = body ? JSON.parse(body) : {};
        } catch (e) {
          // keep raw text
        }

        resolve({
          status: res.statusCode,
          data: parsed,
          headers: res.headers
        });
      });
    });

    req.on('error', reject);

    if (payload) {
      req.write(payload);
    }
    req.end();
  });
}

async function initCsrf(session) {
  const res = await request('GET', '/api/csrf-token', {
    session,
    requireCsrf: false
  });

  if (res.status === 200 && res.data && res.data.csrfToken) {
    session.csrfToken = res.data.csrfToken;
  }

  return res;
}

function assert(condition, message) {
  if (!condition) {
    throw new Error(message);
  }
}

function warn(message) {
  testResults.warnings.push(message);
  console.log(`[WARN] ${message}`);
}

async function test(name, fn) {
  try {
    await fn();
    testResults.passed.push(name);
    console.log(`[PASS] ${name}`);
  } catch (error) {
    testResults.failed.push({ name, error: error.message });
    console.log(`[FAIL] ${name}: ${error.message}`);
  }
}

function ensureTestUser() {
  if (state.testUserId) {
    return;
  }

  const suffix = Date.now();
  const username = `admin_test_user_${suffix}`;
  const email = `${username}@test.local`;
  const password = `AdminTest#${suffix}`;

  const id = UserDB.create({
    username,
    email,
    password,
    is_verified: 1
  });

  UserDB.update(id, {
    is_active: 1,
    is_banned: 0,
    storage_permission: 'user_choice',
    current_storage_type: 'oss'
  });

  state.testUserId = id;
}

function cleanupTestUser() {
  if (!state.testUserId) return;
  try {
    UserDB.delete(state.testUserId);
  } catch (error) {
    warn(`清理测试用户失败: ${error.message}`);
  } finally {
    state.testUserId = null;
  }
}

// 1. 安全检查：未认证访问应被拒绝
async function testUnauthorizedAccess() {
  const res = await request('GET', '/api/admin/users');
  assert(res.status === 401, `未认证访问应返回401，实际返回: ${res.status}`);
}

// 2. 安全检查：无效 Token 应被拒绝
async function testInvalidTokenAccess() {
  const res = await request('GET', '/api/admin/users', {
    headers: {
      Authorization: 'Bearer invalid-token'
    }
  });
  assert(res.status === 401, `无效token应返回401，实际: ${res.status}`);
}

// 3. 管理员登录（基于 Cookie）
async function testAdminLogin() {
  await initCsrf(state.adminSession);

  const res = await request('POST', '/api/login', {
    data: {
      username: 'admin',
      password: 'admin123'
    },
    session: state.adminSession,
    requireCsrf: false
  });

  assert(res.status === 200, `登录应返回200，实际: ${res.status}`);
  assert(res.data && res.data.success === true, `登录失败: ${res.data?.message || 'unknown'}`);
  assert(!!state.adminSession.cookies.token, '登录后应写入 token Cookie');

  await initCsrf(state.adminSession);

  const profileRes = await request('GET', '/api/user/profile', {
    session: state.adminSession
  });

  assert(profileRes.status === 200, `读取profile应返回200，实际: ${profileRes.status}`);
  assert(profileRes.data?.success === true, '读取profile应成功');
  assert(profileRes.data?.user?.is_admin === 1, '登录账号应为管理员');

  state.adminUserId = profileRes.data.user.id;
  assert(Number.isInteger(state.adminUserId) && state.adminUserId > 0, '应获取管理员ID');
}

// 4. 用户列表获取（分页）
async function testGetUsers() {
  const res = await request('GET', '/api/admin/users?paged=1&page=1&pageSize=20&sort=created_desc', {
    session: state.adminSession
  });

  assert(res.status === 200, `应返回200，实际: ${res.status}`);
  assert(res.data?.success === true, '应返回success: true');
  assert(Array.isArray(res.data?.users), 'users应为数组');
  assert(!!res.data?.pagination, '分页模式应返回pagination');
}

// 5. 系统设置获取
async function testGetSettings() {
  const res = await request('GET', '/api/admin/settings', {
    session: state.adminSession
  });

  assert(res.status === 200, `应返回200，实际: ${res.status}`);
  assert(res.data?.success === true, '应返回success: true');
  assert(res.data?.settings && typeof res.data.settings === 'object', '应包含settings对象');
  assert(res.data?.settings?.smtp && typeof res.data.settings.smtp === 'object', '应包含smtp配置');
  assert(res.data?.settings?.global_theme !== undefined, '应包含全局主题设置');

  state.latestSettings = res.data.settings;
}

// 6. 更新系统设置（写回当前值，避免影响测试环境）
async function testUpdateSettings() {
  const current = state.latestSettings || {};
  const payload = {
    global_theme: current.global_theme || 'dark',
    max_upload_size: Number(current.max_upload_size || 10737418240)
  };

  const res = await request('POST', '/api/admin/settings', {
    data: payload,
    session: state.adminSession
  });

  assert(res.status === 200, `应返回200，实际: ${res.status}`);
  assert(res.data?.success === true, '应返回success: true');
}

// 7. 健康检查
async function testHealthCheck() {
  const res = await request('GET', '/api/admin/health-check', {
    session: state.adminSession
  });

  assert(res.status === 200, `应返回200，实际: ${res.status}`);
  assert(res.data?.success === true, '应返回success: true');
  assert(Array.isArray(res.data?.checks), '应包含checks数组');
  assert(res.data?.summary && typeof res.data.summary === 'object', '应包含summary');
}

// 8. 存储统计
async function testStorageStats() {
  const res = await request('GET', '/api/admin/storage-stats', {
    session: state.adminSession
  });

  assert(res.status === 200, `应返回200，实际: ${res.status}`);
  assert(res.data?.success === true, '应返回success: true');
  assert(res.data?.stats && typeof res.data.stats === 'object', '应包含stats对象');
}

// 9. 系统日志获取
async function testGetLogs() {
  const res = await request('GET', '/api/admin/logs?page=1&pageSize=10', {
    session: state.adminSession
  });

  assert(res.status === 200, `应返回200，实际: ${res.status}`);
  assert(res.data?.success === true, '应返回success: true');
  assert(Array.isArray(res.data?.logs), 'logs应为数组');
}

// 10. 日志统计
async function testLogStats() {
  const res = await request('GET', '/api/admin/logs/stats', {
    session: state.adminSession
  });

  assert(res.status === 200, `应返回200，实际: ${res.status}`);
  assert(res.data?.success === true, '应返回success: true');
  assert(res.data?.stats && typeof res.data.stats === 'object', '应包含stats对象');
}

// 11. 分享列表获取
async function testGetShares() {
  const res = await request('GET', '/api/admin/shares', {
    session: state.adminSession
  });

  assert(res.status === 200, `应返回200，实际: ${res.status}`);
  assert(res.data?.success === true, '应返回success: true');
  assert(Array.isArray(res.data?.shares), 'shares应为数组');
}

// 12. 不能封禁自己
async function testCannotBanSelf() {
  assert(state.adminUserId, '管理员ID未初始化');

  const res = await request('POST', `/api/admin/users/${state.adminUserId}/ban`, {
    data: { banned: true },
    session: state.adminSession
  });

  assert(res.status === 400, `封禁自己应返回400，实际: ${res.status}`);
  assert(String(res.data?.message || '').includes('不能封禁自己'), '应提示不能封禁自己');
}

// 13. 不能删除自己
async function testCannotDeleteSelf() {
  assert(state.adminUserId, '管理员ID未初始化');

  const res = await request('DELETE', `/api/admin/users/${state.adminUserId}`, {
    session: state.adminSession
  });

  assert(res.status === 400, `删除自己应返回400，实际: ${res.status}`);
  assert(String(res.data?.message || '').includes('不能删除自己'), '应提示不能删除自己');
}

// 14. 参数验证：无效用户ID
async function testInvalidUserId() {
  const res = await request('POST', '/api/admin/users/invalid/ban', {
    data: { banned: true },
    session: state.adminSession
  });

  assert(res.status === 400, `无效用户ID应返回400，实际: ${res.status}`);
}

// 15. 参数验证：无效分享ID
async function testInvalidShareId() {
  const res = await request('DELETE', '/api/admin/shares/invalid', {
    session: state.adminSession
  });

  assert(res.status === 400, `无效分享ID应返回400，实际: ${res.status}`);
}

// 16. 存储权限设置
async function testSetStoragePermission() {
  ensureTestUser();

  const res = await request('POST', `/api/admin/users/${state.testUserId}/storage-permission`, {
    data: {
      storage_permission: 'local_only',
      local_storage_quota: 2147483648,
      download_traffic_quota: 3221225472
    },
    session: state.adminSession
  });

  assert(res.status === 200, `应返回200，实际: ${res.status}`);
  assert(res.data?.success === true, '应返回success: true');
}

// 17. 参数验证：无效的存储权限值
async function testInvalidStoragePermission() {
  ensureTestUser();

  const res = await request('POST', `/api/admin/users/${state.testUserId}/storage-permission`, {
    data: { storage_permission: 'invalid_permission' },
    session: state.adminSession
  });

  assert(res.status === 400, `无效存储权限应返回400，实际: ${res.status}`);
}

// 18. 主题设置验证
async function testInvalidTheme() {
  const res = await request('POST', '/api/admin/settings', {
    data: { global_theme: 'invalid_theme' },
    session: state.adminSession
  });

  assert(res.status === 400, `无效主题应返回400，实际: ${res.status}`);
}

// 19. 日志清理测试
async function testLogCleanup() {
  const res = await request('POST', '/api/admin/logs/cleanup', {
    data: { keepDays: 90 },
    session: state.adminSession
  });

  assert(res.status === 200, `应返回200，实际: ${res.status}`);
  assert(res.data?.success === true, '应返回success: true');
  assert(typeof res.data?.deletedCount === 'number', 'deletedCount应为数字');
}

// 20. SMTP测试（未配置时返回400，配置后可能200/500）
async function testSmtpTest() {
  const res = await request('POST', '/api/admin/settings/test-smtp', {
    data: { to: 'test@example.com' },
    session: state.adminSession
  });

  if (res.status === 400 && String(res.data?.message || '').includes('SMTP未配置')) {
    console.log('  - SMTP未配置，这是预期的');
    return;
  }

  assert(res.status === 200 || res.status === 500, `应返回200或500，实际: ${res.status}`);
}

// 21. 上传工具配置生成（替代已移除的 /api/admin/check-upload-tool）
async function testGenerateUploadToolConfig() {
  const res = await request('POST', '/api/upload/generate-tool', {
    data: {},
    session: state.adminSession
  });

  assert(res.status === 200, `应返回200，实际: ${res.status}`);
  assert(res.data?.success === true, '应返回success: true');
  assert(res.data?.config && typeof res.data.config === 'object', '应包含config对象');
  assert(typeof res.data?.config?.api_key === 'string' && res.data.config.api_key.length > 0, '应返回有效api_key');
}

// 22. 用户文件查看 - 无效用户ID验证
async function testInvalidUserIdForFiles() {
  const res = await request('GET', '/api/admin/users/invalid/files', {
    session: state.adminSession
  });

  assert(res.status === 400, `无效用户ID应返回400，实际: ${res.status}`);
}

// 23. 删除用户 - 无效用户ID验证
async function testInvalidUserIdForDelete() {
  const res = await request('DELETE', '/api/admin/users/invalid', {
    session: state.adminSession
  });

  assert(res.status === 400, `无效用户ID应返回400，实际: ${res.status}`);
}

// 24. 存储权限设置 - 无效用户ID验证
async function testInvalidUserIdForPermission() {
  const res = await request('POST', '/api/admin/users/invalid/storage-permission', {
    data: {
      storage_permission: 'local_only'
    },
    session: state.adminSession
  });

  assert(res.status === 400, `无效用户ID应返回400，实际: ${res.status}`);
}

async function runTests() {
  console.log('========================================');
  console.log('管理员功能完整性测试（Cookie + CSRF）');
  console.log('========================================\n');

  console.log('\n--- 安全检查 ---');
  await test('未认证访问应被拒绝', testUnauthorizedAccess);
  await test('无效token应被拒绝', testInvalidTokenAccess);

  await test('管理员登录', testAdminLogin);

  console.log('\n--- 用户管理 ---');
  await test('获取用户列表', testGetUsers);
  await test('不能封禁自己', testCannotBanSelf);
  await test('不能删除自己', testCannotDeleteSelf);
  await test('无效用户ID验证', testInvalidUserId);
  await test('设置存储权限', testSetStoragePermission);
  await test('无效存储权限验证', testInvalidStoragePermission);

  console.log('\n--- 系统设置 ---');
  await test('获取系统设置', testGetSettings);
  await test('更新系统设置', testUpdateSettings);
  await test('无效主题验证', testInvalidTheme);
  await test('SMTP测试', testSmtpTest);

  console.log('\n--- 分享管理 ---');
  await test('获取分享列表', testGetShares);
  await test('无效分享ID验证', testInvalidShareId);

  console.log('\n--- 系统监控 ---');
  await test('健康检查', testHealthCheck);
  await test('存储统计', testStorageStats);
  await test('获取系统日志', testGetLogs);
  await test('日志统计', testLogStats);
  await test('日志清理', testLogCleanup);

  console.log('\n--- 其他功能 ---');
  await test('上传工具配置生成', testGenerateUploadToolConfig);

  console.log('\n--- 参数验证增强 ---');
  await test('用户文件查看无效ID验证', testInvalidUserIdForFiles);
  await test('删除用户无效ID验证', testInvalidUserIdForDelete);
  await test('存储权限设置无效ID验证', testInvalidUserIdForPermission);

  cleanupTestUser();

  console.log('\n========================================');
  console.log('测试结果汇总');
  console.log('========================================');
  console.log(`通过: ${testResults.passed.length}`);
  console.log(`失败: ${testResults.failed.length}`);
  console.log(`警告: ${testResults.warnings.length}`);

  if (testResults.failed.length > 0) {
    console.log('\n失败的测试:');
    for (const f of testResults.failed) {
      console.log(`  - ${f.name}: ${f.error}`);
    }
  }

  if (testResults.warnings.length > 0) {
    console.log('\n警告:');
    for (const w of testResults.warnings) {
      console.log(`  - ${w}`);
    }
  }

  console.log('\n========================================');

  process.exit(testResults.failed.length > 0 ? 1 : 0);
}

runTests().catch((error) => {
  cleanupTestUser();
  console.error('测试执行异常:', error);
  process.exit(1);
});
