const { Client } = require('../../backend/node_modules/pg');
const { performance } = require('perf_hooks');
const {
  config,
  ensureDir,
  explainSql,
  explainSummary,
  query02Dir,
  query02Sql,
  summarizeRows,
  writeCsv,
  writeJson
} = require('./query02-lib');
const { getDbConfig } = require('./benchmark-lib');

const levels = String(process.env.BENCHMARK_CONCURRENCY_LEVELS || config.concurrencyLevels.join(','))
  .split(',')
  .map((item) => Number.parseInt(item.trim(), 10))
  .filter((item) => Number.isFinite(item) && item > 0);
const requestsPerLevel = Number.parseInt(
  process.env.BENCHMARK_CONCURRENCY_REQUESTS || config.concurrencyRequestsPerLevel,
  10
);

const activeConnections = async (client) => {
  try {
    const { rows } = await client.query(
      "SELECT COUNT(*)::int AS active FROM pg_stat_activity WHERE datname = current_database() AND state <> 'idle'"
    );
    return Number(rows[0]?.active || 0);
  } catch {
    return null;
  }
};

const runPool = async (items, workers, task) => {
  let index = 0;
  const worker = async () => {
    while (index < items.length) {
      const current = items[index];
      index += 1;
      await task(current);
    }
  };
  await Promise.all(Array.from({ length: Math.min(workers, items.length) }, () => worker()));
};

const runOne = async (level, repetition) => {
  const timestamp = new Date().toISOString();
  const client = new Client(getDbConfig(level));
  const connectStarted = performance.now();
  await client.connect();
  const connectMs = performance.now() - connectStarted;
  const started = performance.now();

  try {
    const result = await client.query(explainSql(query02Sql));
    const endpointTotal = performance.now() - started + connectMs;
    const summary = explainSummary(result.rows[0]['QUERY PLAN'][0]);
    const active = await activeConnections(client);
    return {
      phase: 'query02_concurrency',
      concurrency_level: level,
      query_id: 'query_02',
      query_name: 'Catalogo general paginado LIMIT 25',
      query_group: 'estructurada',
      repetition,
      timestamp,
      connection_acquire_ms: connectMs,
      endpoint_total_ms: endpointTotal,
      sql_ms: summary.execution_ms,
      planning_ms: summary.planning_ms,
      execution_ms: summary.execution_ms,
      rows_returned: summary.actual_rows,
      estimated_rows: summary.estimated_rows,
      actual_rows: summary.actual_rows,
      shared_hit_blocks: summary.shared_hit_blocks,
      shared_read_blocks: summary.shared_read_blocks,
      temp_read_blocks: summary.temp_read_blocks,
      temp_written_blocks: summary.temp_written_blocks,
      active_pg_connections: active,
      cpu_percent_process: 0,
      memory_rss_mb: process.memoryUsage().rss / 1024 / 1024,
      disk_fs_read_ops: 0,
      disk_fs_write_ops: 0,
      success: true,
      error_message: ''
    };
  } catch (error) {
    return {
      phase: 'query02_concurrency',
      concurrency_level: level,
      query_id: 'query_02',
      query_name: 'Catalogo general paginado LIMIT 25',
      query_group: 'estructurada',
      repetition,
      timestamp,
      connection_acquire_ms: connectMs,
      endpoint_total_ms: performance.now() - started + connectMs,
      sql_ms: null,
      planning_ms: null,
      execution_ms: null,
      rows_returned: 0,
      estimated_rows: null,
      actual_rows: null,
      shared_hit_blocks: null,
      shared_read_blocks: null,
      temp_read_blocks: null,
      temp_written_blocks: null,
      active_pg_connections: null,
      cpu_percent_process: 0,
      memory_rss_mb: process.memoryUsage().rss / 1024 / 1024,
      disk_fs_read_ops: 0,
      disk_fs_write_ops: 0,
      success: false,
      error_message: String(error?.message || error)
    };
  } finally {
    await client.end();
  }
};

const main = async () => {
  ensureDir(query02Dir);
  const raw = [];

  for (const level of levels) {
    const work = Array.from({ length: requestsPerLevel }, (_, index) => index + 1);
    await runPool(work, level, async (repetition) => {
      const row = await runOne(level, repetition);
      raw.push(row);
      process.stdout.write(
        `query02 concurrency=${level} ${repetition}/${requestsPerLevel} ${row.success ? 'ok' : 'fail'} ${row.endpoint_total_ms.toFixed(2)}ms\n`
      );
    });
  }

  raw.sort((a, b) => a.concurrency_level - b.concurrency_level || a.repetition - b.repetition);
  const summary = summarizeRows(raw, [
    'phase',
    'concurrency_level',
    'query_id',
    'query_name',
    'query_group'
  ]);
  writeCsv(`${query02Dir}/concurrency_raw.csv`, raw);
  writeCsv(`${query02Dir}/concurrency_summary.csv`, summary);
  writeJson(`${query02Dir}/concurrency.json`, {
    generatedAt: new Date().toISOString(),
    levels,
    requestsPerLevel,
    summary
  });
};

main().catch((error) => {
  console.error(error);
  process.exit(1);
});
