/**
 * 用户管理系统 (UMS) - k6 全场景性能测试套件
 *
 * 测试策略：
 *   Stage 1 - 预热阶段 (2min): 从 0 → 10 VU，验证系统基线
 *   Stage 2 - 正常负载 (5min): 50 VU，验证日常运营能力
 *   Stage 3 - 峰值负载 (3min): 100 VU，验证高峰时段
 *   Stage 4 - 持续峰值 (5min): 100 VU，验证耐久性
 *   Stage 5 - 压力测试 (2min): 200 VU，寻找系统断点
 *   Stage 6 - 尖峰测试 (1min): 500 VU，模拟流量骤增
 *   Stage 7 - 冷却阶段 (2min): 200 → 0 VU
 *
 * 运行命令:
 *   k6 run --env BASE_URL=http://localhost:8080 docs/performance/k6_load_test.js
 *   k6 run --env BASE_URL=http://localhost:8080 --env SCENARIO=smoke docs/performance/k6_load_test.js
 */

import http from 'k6/http';
import { check, sleep, group } from 'k6';
import { Rate, Trend, Counter, Gauge } from 'k6/metrics';
import { SharedArray } from 'k6/data';
import exec from 'k6/execution';

// ─────────────────────────────────────────────
// 自定义指标
// ─────────────────────────────────────────────
const loginErrorRate    = new Rate('login_errors');
const apiErrorRate      = new Rate('api_errors');
const loginLatency      = new Trend('login_latency_ms', true);
const userQueryLatency  = new Trend('user_query_latency_ms', true);
const tokenRefreshLatency = new Trend('token_refresh_latency_ms', true);
const authRequests      = new Counter('authenticated_requests');
const activeSessionGauge = new Gauge('active_sessions');

const BASE_URL = __ENV.BASE_URL || 'http://localhost:8080';
const SCENARIO = __ENV.SCENARIO || 'full';

// ─────────────────────────────────────────────
// 测试场景配置
// ─────────────────────────────────────────────
const scenarios = {
  smoke: {
    stages: [
      { duration: '30s', target: 5 },
      { duration: '1m',  target: 5 },
      { duration: '30s', target: 0 },
    ],
  },
  full: {
    stages: [
      { duration: '2m',  target: 10  },  // 预热
      { duration: '5m',  target: 50  },  // 正常负载
      { duration: '3m',  target: 100 },  // 峰值负载
      { duration: '5m',  target: 100 },  // 持续峰值（耐久）
      { duration: '2m',  target: 200 },  // 压力测试
      { duration: '1m',  target: 500 },  // 尖峰测试
      { duration: '2m',  target: 0   },  // 冷却
    ],
  },
  stress: {
    stages: [
      { duration: '2m',  target: 200 },
      { duration: '5m',  target: 200 },
      { duration: '2m',  target: 400 },
      { duration: '5m',  target: 400 },
      { duration: '2m',  target: 0   },
    ],
  },
  soak: {
    stages: [
      { duration: '2m',  target: 50  },
      { duration: '30m', target: 50  },  // 耐力测试 30 分钟
      { duration: '2m',  target: 0   },
    ],
  },
};

export const options = {
  stages: scenarios[SCENARIO]?.stages || scenarios.full.stages,
  thresholds: {
    // HTTP 级别 SLA
    http_req_duration:         ['p(95)<500', 'p(99)<1000'],
    http_req_failed:           ['rate<0.01'],     // 错误率 < 1%

    // 业务级别 SLA
    login_latency_ms:          ['p(95)<300', 'p(99)<800'],
    user_query_latency_ms:     ['p(95)<200', 'p(99)<500'],
    token_refresh_latency_ms:  ['p(95)<150', 'p(99)<400'],

    // 错误率
    login_errors:              ['rate<0.02'],     // 登录错误率 < 2%
    api_errors:                ['rate<0.01'],     // API 错误率 < 1%
  },
  summaryTrendStats: ['avg', 'min', 'med', 'max', 'p(90)', 'p(95)', 'p(99)', 'count'],
};

// ─────────────────────────────────────────────
// 辅助函数
// ─────────────────────────────────────────────
function getCsrfToken() {
  const res = http.get(`${BASE_URL}/api/v1/auth/csrf-token`, {
    headers: { 'Content-Type': 'application/json' },
  });
  if (res.status === 200) {
    try {
      return res.json('csrf_token') || res.json('data.csrf_token') || '';
    } catch (_) {
      return '';
    }
  }
  return '';
}

function login(username, password, csrfToken) {
  const start = Date.now();
  const payload = JSON.stringify({
    account:        username,
    password:       password,
    device_id:      `load-test-device-${exec.vu.idInTest}`,
    device_name:    'k6-load-tester',
    device_browser: 'k6',
    device_os:      'linux',
  });

  const res = http.post(`${BASE_URL}/api/v1/auth/login`, payload, {
    headers: {
      'Content-Type':  'application/json',
      'X-CSRF-Token':  csrfToken,
    },
  });

  const latencyMs = Date.now() - start;
  loginLatency.add(latencyMs);

  const success = check(res, {
    '登录状态200':          (r) => r.status === 200,
    '返回access_token':     (r) => {
      try {
        const body = r.json();
        return !!(body.access_token || (body.data && body.data.access_token));
      } catch (_) { return false; }
    },
    '登录延迟<800ms':       (_) => latencyMs < 800,
  });

  loginErrorRate.add(!success);
  return res.status === 200 ? res : null;
}

function getAccessToken(loginRes) {
  if (!loginRes) return null;
  try {
    const body = loginRes.json();
    return body.access_token || (body.data && body.data.access_token) || null;
  } catch (_) { return null; }
}

function authHeaders(token, csrfToken) {
  return {
    headers: {
      'Authorization': `Bearer ${token}`,
      'Content-Type':  'application/json',
      'X-CSRF-Token':  csrfToken || '',
    },
  };
}

// ─────────────────────────────────────────────
// 测试场景主函数
// ─────────────────────────────────────────────
export default function () {
  const csrfToken = getCsrfToken();
  sleep(0.1);

  // ── 场景1: 认证流程 (权重 30%) ──────────────
  group('认证流程', function () {
    const loginRes = login('admin', 'Admin@123456', csrfToken);
    if (!loginRes) { sleep(1); return; }

    const token = getAccessToken(loginRes);
    if (!token) { sleep(1); return; }

    activeSessionGauge.add(1);
    authRequests.add(1);

    // 获取用户信息
    const userInfoRes = http.get(`${BASE_URL}/api/v1/auth/userinfo`, authHeaders(token, csrfToken));
    check(userInfoRes, {
      '用户信息200': (r) => r.status === 200,
      '包含用户名':  (r) => {
        try { return !!r.json('username'); } catch (_) { return false; }
      },
    });
    apiErrorRate.add(userInfoRes.status !== 200);

    sleep(0.5 + Math.random() * 0.5);

    // ── 场景2: 用户管理操作 (权重 40%) ──────────
    group('用户管理', function () {
      const start = Date.now();
      const listRes = http.get(
        `${BASE_URL}/api/v1/users?page=1&page_size=20`,
        authHeaders(token, csrfToken)
      );
      const latencyMs = Date.now() - start;
      userQueryLatency.add(latencyMs);

      const listOk = check(listRes, {
        '用户列表200':        (r) => r.status === 200,
        '返回数据数组':       (r) => {
          try {
            const body = r.json();
            return Array.isArray(body.data) || Array.isArray(body.items) ||
                   (body.data && Array.isArray(body.data.list));
          } catch (_) { return false; }
        },
        '查询延迟<500ms':     (_) => latencyMs < 500,
      });
      apiErrorRate.add(!listOk);

      sleep(0.2 + Math.random() * 0.3);

      // 角色列表查询
      const rolesRes = http.get(`${BASE_URL}/api/v1/roles`, authHeaders(token, csrfToken));
      check(rolesRes, {
        '角色列表200': (r) => r.status === 200,
      });
      apiErrorRate.add(rolesRes.status !== 200);

      sleep(0.2);
    });

    // ── 场景3: 日志查询（分页）──────────────────
    group('日志查询', function () {
      // offset 分页
      const logRes = http.get(
        `${BASE_URL}/api/v1/logs/login?page=1&page_size=20`,
        authHeaders(token, csrfToken)
      );
      check(logRes, {
        '日志列表200': (r) => r.status === 200,
      });

      sleep(0.3 + Math.random() * 0.2);

      // cursor 分页（深翻）
      const cursorRes = http.get(
        `${BASE_URL}/api/v1/logs/login?size=20`,
        authHeaders(token, csrfToken)
      );
      check(cursorRes, {
        'cursor分页200': (r) => r.status === 200,
      });

      sleep(0.2);
    });

    // ── 场景4: Token 刷新 (每10次请求模拟一次) ──
    if (exec.vu.iterationInScenario % 10 === 0) {
      group('Token刷新', function () {
        const start = Date.now();
        const refreshRes = http.post(
          `${BASE_URL}/api/v1/auth/refresh`,
          null,
          authHeaders(token, csrfToken)
        );
        const latencyMs = Date.now() - start;
        tokenRefreshLatency.add(latencyMs);

        check(refreshRes, {
          '刷新成功200或401': (r) => r.status === 200 || r.status === 401,
        });
        sleep(0.1);
      });
    }

    activeSessionGauge.add(-1);
    sleep(1 + Math.random() * 1);
  });
}

// ─────────────────────────────────────────────
// 测试结束汇总
// ─────────────────────────────────────────────
export function handleSummary(data) {
  const now = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);

  function formatMetric(metric) {
    if (!metric || !metric.values) return 'N/A';
    const v = metric.values;
    if (v.rate !== undefined) return `${(v.rate * 100).toFixed(2)}%`;
    if (v['p(99)'] !== undefined) {
      return `avg=${v.avg?.toFixed(1)}ms p50=${v.med?.toFixed(1)}ms p95=${v['p(95)']?.toFixed(1)}ms p99=${v['p(99)']?.toFixed(1)}ms max=${v.max?.toFixed(1)}ms`;
    }
    return JSON.stringify(v);
  }

  const report = {
    summary: {
      test_time:    now,
      scenario:     SCENARIO,
      base_url:     BASE_URL,
      total_requests:  data.metrics.http_reqs?.values?.count,
      total_duration:  data.state?.testRunDurationMs,
      peak_vus:        data.metrics.vus_max?.values?.max,
    },
    sla_results: {
      http_req_duration_p99:     formatMetric(data.metrics.http_req_duration),
      http_req_failed_rate:      formatMetric(data.metrics.http_req_failed),
      login_latency_p99:         formatMetric(data.metrics.login_latency_ms),
      user_query_latency_p99:    formatMetric(data.metrics.user_query_latency_ms),
      token_refresh_latency_p99: formatMetric(data.metrics.token_refresh_latency_ms),
      login_error_rate:          formatMetric(data.metrics.login_errors),
      api_error_rate:            formatMetric(data.metrics.api_errors),
    },
    raw_metrics: data.metrics,
  };

  return {
    [`docs/performance/results/k6_result_${now}.json`]: JSON.stringify(report, null, 2),
    stdout: generateTextSummary(data, report),
  };
}

function generateTextSummary(data, report) {
  const thresholds = data.metrics;
  const passed = Object.entries(data.metrics)
    .filter(([, m]) => m.thresholds)
    .every(([, m]) => Object.values(m.thresholds).every(t => !t.ok === false));

  return `
╔══════════════════════════════════════════════════════════════════╗
║              UMS 性能测试报告 (k6)                               ║
╚══════════════════════════════════════════════════════════════════╝

📊 测试概要
  场景:          ${report.summary.scenario}
  目标地址:      ${report.summary.base_url}
  总请求数:      ${report.summary.total_requests?.toLocaleString() || 'N/A'}
  峰值 VU:       ${report.summary.peak_vus || 'N/A'}

⚡ SLA 结果
  HTTP P99:      ${report.sla_results.http_req_duration_p99}
  HTTP 错误率:   ${report.sla_results.http_req_failed_rate}
  登录 P99:      ${report.sla_results.login_latency_p99}
  用户查询 P99:  ${report.sla_results.user_query_latency_p99}
  Token刷新 P99: ${report.sla_results.token_refresh_latency_p99}

📝 详细结果已写入 docs/performance/results/
`;
}
