/**
 * Context Tracker — Real-time token monitoring
 *
 * Tracks token usage per thread/session, detects peak usage moments,
 * calculates averages, and identifies optimization opportunities.
 * Integrates with analytics-engine to record context events.
 */

import { recordContextEvent } from '../analytics/analytics-engine.js';
import { addThreadEvent } from '../threads/thread-manager.js';

// ============================================================================
// Constants
// ============================================================================

const WARNING_THRESHOLD = 0.75;   // 75% of context window
const CRITICAL_THRESHOLD = 0.90;  // 90% of context window

export const OPTIMIZATION_STRATEGIES = {
  MCP_HYGIENE: 'mcp_hygiene',
  MICRO_AGENT: 'micro_agent_switch',
  CONTEXT_BUNDLE: 'context_bundle',
  PRIMING_FILE: 'priming_file',
  STANDARDS_SUBSET: 'standards_subset'
};

// In-memory session state (not persisted — resets each session)
const sessions = new Map();

// ============================================================================
// Session Management
// ============================================================================

/**
 * Start tracking a session
 * @param {Object} opts
 * @param {string} opts.feature - Feature name
 * @param {string} [opts.threadId] - Thread ID
 * @param {number} [opts.contextWindow=200000] - Model context window size
 * @param {string} [opts.model] - Model name
 * @returns {string} Session ID
 */
export function startSession({ feature, threadId = null, contextWindow = 200000, model = 'claude-sonnet-4-6' }) {
  const sessionId = threadId || `session-${Date.now()}`;

  sessions.set(sessionId, {
    sessionId,
    feature,
    threadId,
    model,
    contextWindow,
    startedAt: new Date().toISOString(),
    peakUsage: 0,
    currentUsage: 0,
    samples: [],
    events: []
  });

  recordContextEvent({
    type: 'context_session_started',
    feature,
    threadId,
    data: { model, contextWindow }
  });

  return sessionId;
}

/**
 * Record a token usage sample for a session
 * @param {string} sessionId - Session ID
 * @param {Object} usage
 * @param {number} usage.tokensUsed - Total tokens in context
 * @param {Object} [usage.breakdown] - Token breakdown by source
 * @returns {Object} Current session state with any optimization recommendations
 */
export function recordTokenUsage(sessionId, { tokensUsed, breakdown = {} }) {
  const session = sessions.get(sessionId);
  if (!session) {
    throw new Error(`Session not found: ${sessionId}`);
  }

  const utilization = tokensUsed / session.contextWindow;
  session.currentUsage = tokensUsed;

  if (tokensUsed > session.peakUsage) {
    session.peakUsage = tokensUsed;
  }

  const sample = {
    timestamp: new Date().toISOString(),
    tokensUsed,
    utilization: Math.round(utilization * 100) / 100,
    breakdown
  };
  session.samples.push(sample);

  // Record to analytics
  recordContextEvent({
    type: 'token_usage',
    feature: session.feature,
    threadId: session.threadId,
    data: { tokensUsed, utilization, breakdown }
  });

  // Check thresholds and identify opportunities
  const recommendations = identifyOptimizations(session, utilization);

  if (utilization >= CRITICAL_THRESHOLD) {
    const event = { type: 'context_critical', utilization, recommendations };
    session.events.push(event);

    if (session.threadId) {
      try {
        addThreadEvent(session.threadId, 'context_critical', { utilization });
      } catch {
        // Thread may not exist in state yet
      }
    }

    recordContextEvent({
      type: 'context_critical',
      feature: session.feature,
      threadId: session.threadId,
      data: { utilization, tokensUsed, recommendations }
    });
  } else if (utilization >= WARNING_THRESHOLD) {
    recordContextEvent({
      type: 'context_warning',
      feature: session.feature,
      threadId: session.threadId,
      data: { utilization, tokensUsed }
    });
  }

  return { session, recommendations };
}

/**
 * End a session and record summary
 * @param {string} sessionId - Session ID
 * @returns {Object} Session summary
 */
export function endSession(sessionId) {
  const session = sessions.get(sessionId);
  if (!session) return null;

  const avgUsage = session.samples.length > 0
    ? Math.round(session.samples.reduce((sum, s) => sum + s.tokensUsed, 0) / session.samples.length)
    : 0;

  const summary = {
    sessionId,
    feature: session.feature,
    model: session.model,
    startedAt: session.startedAt,
    endedAt: new Date().toISOString(),
    peakUsage: session.peakUsage,
    avgUsage,
    samples: session.samples.length,
    criticalMoments: session.events.filter(e => e.type === 'context_critical').length
  };

  recordContextEvent({
    type: 'context_session_ended',
    feature: session.feature,
    threadId: session.threadId,
    data: summary
  });

  sessions.delete(sessionId);
  return summary;
}

// ============================================================================
// Optimization Analysis
// ============================================================================

/**
 * Identify context optimization opportunities based on current utilization
 * @param {Object} session - Session object
 * @param {number} utilization - Current utilization (0-1)
 * @returns {Array} Array of optimization recommendations
 */
export function identifyOptimizations(session, utilization) {
  const recommendations = [];

  if (utilization >= 0.5) {
    recommendations.push({
      strategy: OPTIMIZATION_STRATEGIES.MCP_HYGIENE,
      description: 'Disable unused MCP servers to free ~15-30K tokens',
      estimatedSavings: '15,000-30,000 tokens',
      priority: utilization >= 0.75 ? 'high' : 'medium'
    });
  }

  if (utilization >= 0.65) {
    recommendations.push({
      strategy: OPTIMIZATION_STRATEGIES.STANDARDS_SUBSET,
      description: 'Load only task-relevant standards instead of all standards',
      estimatedSavings: '10,000-20,000 tokens',
      priority: 'medium'
    });
  }

  if (utilization >= 0.80) {
    recommendations.push({
      strategy: OPTIMIZATION_STRATEGIES.MICRO_AGENT,
      description: 'Switch to a micro-agent with minimal context for focused tasks',
      estimatedSavings: '50,000-100,000 tokens',
      priority: 'high'
    });
    recommendations.push({
      strategy: OPTIMIZATION_STRATEGIES.PRIMING_FILE,
      description: 'Use a 500-token priming file instead of full CLAUDE.md',
      estimatedSavings: '22,000 tokens',
      priority: 'high'
    });
  }

  if (utilization >= 0.90) {
    recommendations.push({
      strategy: OPTIMIZATION_STRATEGIES.CONTEXT_BUNDLE,
      description: 'Create a context bundle checkpoint (180K → 15K token compression)',
      estimatedSavings: '165,000 tokens',
      priority: 'critical'
    });
  }

  return recommendations;
}

/**
 * Get statistics for a session
 * @param {string} sessionId - Session ID
 * @returns {Object|null} Session statistics
 */
export function getSessionStats(sessionId) {
  const session = sessions.get(sessionId);
  if (!session) return null;

  const avgUsage = session.samples.length > 0
    ? Math.round(session.samples.reduce((sum, s) => sum + s.tokensUsed, 0) / session.samples.length)
    : 0;

  return {
    sessionId,
    feature: session.feature,
    model: session.model,
    contextWindow: session.contextWindow,
    currentUsage: session.currentUsage,
    peakUsage: session.peakUsage,
    avgUsage,
    peakUtilization: Math.round(session.peakUsage / session.contextWindow * 100),
    currentUtilization: Math.round(session.currentUsage / session.contextWindow * 100),
    samples: session.samples.length
  };
}

/**
 * Get all active sessions
 * @returns {Array} Active session summaries
 */
export function getActiveSessions() {
  return Array.from(sessions.values()).map(s => ({
    sessionId: s.sessionId,
    feature: s.feature,
    model: s.model,
    currentUsage: s.currentUsage,
    peakUsage: s.peakUsage,
    utilization: Math.round(s.currentUsage / s.contextWindow * 100)
  }));
}
