'use strict';

const { resolveApiBaseUrl } = require('./ctm-context-client');

const DEFAULT_TIMEOUT_MS = 1000;

function apiDisabled(env = process.env) {
  return env.WALLE_CTM_API_DISABLED === '1' || env.CTM_SESSION_MEMORY_API === '0';
}

async function requestCtmJson(path, options = {}) {
  const env = options.env || process.env;
  if (apiDisabled(env)) {
    const err = new Error('CTM API disabled');
    err.code = 'ctm_api_disabled';
    throw err;
  }
  const baseUrl = resolveApiBaseUrl(env);
  if (!baseUrl) {
    const err = new Error('CTM API base URL missing');
    err.code = 'ctm_api_base_missing';
    throw err;
  }
  const controller = new AbortController();
  const timer = setTimeout(() => controller.abort(), options.timeoutMs || DEFAULT_TIMEOUT_MS);
  try {
    const headers = { Accept: 'application/json' };
    const token = env.CTM_TOKEN || env.WALLE_CTM_TOKEN || env.CTM_API_TOKEN;
    if (token) headers.Authorization = `Bearer ${token}`;
    const response = await fetch(`${baseUrl}${path}`, {
      method: 'GET',
      headers,
      signal: controller.signal,
    });
    const text = await response.text();
    const json = text ? JSON.parse(text) : {};
    if (!response.ok) {
      const err = new Error(json?.error || json?.reason || `ctm_api_http_${response.status}`);
      err.status = response.status;
      throw err;
    }
    return json;
  } finally {
    clearTimeout(timer);
  }
}

async function listPromptExecutions(options = {}) {
  const params = new URLSearchParams();
  params.set('limit', String(Math.max(1, Math.min(Number(options.limit) || 1000, 10000))));
  params.set('order', options.order === 'asc' ? 'asc' : 'desc');
  if (options.since) params.set('after', String(options.since));
  if (options.role) params.set('role', String(options.role));
  const json = await requestCtmJson(`/api/prompt-executions?${params.toString()}`, options);
  return Array.isArray(json.executions) ? json.executions : [];
}

async function getPromptExecutionStats(options = {}) {
  return requestCtmJson('/api/prompt-executions/stats', options);
}

function pairPromptExecutions(rows, options = {}) {
  const bySession = new Map();
  for (const row of rows || []) {
    const sessionId = row.session_id || '';
    if (!sessionId) continue;
    if (!bySession.has(sessionId)) bySession.set(sessionId, []);
    bySession.get(sessionId).push(row);
  }

  const pairs = [];
  for (const [sessionId, sessionRows] of bySession.entries()) {
    sessionRows.sort((a, b) => Number(a.message_index || 0) - Number(b.message_index || 0));
    const userCount = sessionRows.filter((row) => row.role === 'user').length;
    if (options.singleTurnOnly && userCount !== 1) continue;
    const byIndex = new Map(sessionRows.map((row) => [Number(row.message_index || 0), row]));
    for (const row of sessionRows) {
      if (row.role !== 'user') continue;
      const assistant = byIndex.get(Number(row.message_index || 0) + 1);
      if (!assistant || assistant.role !== 'assistant') continue;
      const prompt = row.message_text || '';
      const response = assistant.message_text || '';
      if (prompt.length < 20 || response.length < 20) continue;
      pairs.push({
        session_id: sessionId,
        prompt,
        response,
        executed_at: row.executed_at,
        project_path: row.project_path,
        tool_uses: assistant.tool_uses,
      });
    }
  }
  pairs.sort((a, b) => String(a.executed_at || '').localeCompare(String(b.executed_at || '')));
  return options.limit ? pairs.slice(0, options.limit) : pairs;
}

function groupPromptExecutionsBySession(rows, options = {}) {
  const sessions = new Map();
  for (const row of rows || []) {
    const sessionId = row.session_id || '';
    if (!sessionId) continue;
    if (!sessions.has(sessionId)) sessions.set(sessionId, []);
    sessions.get(sessionId).push(row);
  }
  const out = [];
  for (const [sessionId, messages] of sessions.entries()) {
    messages.sort((a, b) => Number(a.message_index || 0) - Number(b.message_index || 0));
    const userCount = messages.filter((row) => row.role === 'user').length;
    if (options.multiTurnOnly && userCount < 2) continue;
    out.push({
      session_id: sessionId,
      started_at: messages[0]?.executed_at || '',
      msg_count: messages.length,
      messages,
    });
  }
  out.sort((a, b) => String(a.started_at || '').localeCompare(String(b.started_at || '')));
  return options.limit ? out.slice(0, options.limit) : out;
}

module.exports = {
  getPromptExecutionStats,
  groupPromptExecutionsBySession,
  listPromptExecutions,
  pairPromptExecutions,
  requestCtmJson,
};
