/**
 * ProgressAnalystAgent — A2A pipeline for JarvisJr coaching skill progress analysis.
 *
 * Agent roster (3 steps):
 *   1. SessionMetricsCollectorAgent — per agent: list recent sessions, extract skillMetrics timeseries
 *   2. PlateauDetectorAgent         — identify metrics that have not improved across last N sessions
 *   3. ProgressReportAgent          — assemble per-agent recommendations (difficulty change / supplementary agent)
 *
 * MCP tools:
 *   jarvis.progress.analyze(lookbackSessions?, plateauThreshold?) — run pipeline across all agents
 */

import { randomUUID } from 'node:crypto';
import { z } from 'zod';
import { registerTool } from '../tools/registry.js';
import type { McpToolRequest } from '../tools/types.js';
import {
  jarvisAgentsList,
  jarvisSessionsList,
  type JarvisAgentDoc,
  type JarvisSessionDoc,
} from '../../lib/jarvis-client.js';

// ── Types ──────────────────────────────────────────────────────────────────────

interface SkillTrend {
  skill: string;
  scores: number[];
  latest: number;
  earliest: number;
  delta: number;
  isPlateaued: boolean;
}

interface AgentProgressAnalysis {
  agentId: string;
  agentName: string;
  sessionsAnalyzed: number;
  skills: SkillTrend[];
  plateauedSkills: string[];
  recommendation: AgentRecommendation;
}

type AgentRecommendation =
  | { action: 'none'; reason: string }
  | { action: 'increase_difficulty'; currentLevel: string; reason: string }
  | { action: 'supplementary_agent'; suggestedRole: string; reason: string }
  | { action: 'insufficient_data'; reason: string };

export interface ProgressAnalystReport {
  runId: string;
  productId: 'jarvisjr';
  lookbackSessions: number;
  plateauThreshold: number;
  agentsAnalyzed: number;
  agentsWithPlateau: number;
  agentsProgressing: number;
  perAgent: AgentProgressAnalysis[];
  summary: string;
  generatedAt: string;
}

// ── Step 1: SessionMetricsCollectorAgent ──────────────────────────────────────

async function collectAgentMetrics(
  agent: JarvisAgentDoc,
  lookbackSessions: number,
  opts: { token?: string; requestId?: string }
): Promise<{ agent: JarvisAgentDoc; sessions: JarvisSessionDoc[] }> {
  try {
    const result = await jarvisSessionsList({ agentId: agent.id, limit: lookbackSessions }, opts);
    return { agent, sessions: result.sessions };
  } catch {
    return { agent, sessions: [] };
  }
}

// ── Step 2: PlateauDetectorAgent ──────────────────────────────────────────────

function detectPlateaus(sessions: JarvisSessionDoc[], plateauThreshold: number): SkillTrend[] {
  const completed = sessions
    .filter(s => s.status === 'completed' && s.skillMetrics)
    .sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());

  if (completed.length < 2) return [];

  const skillMap = new Map<string, number[]>();
  for (const session of completed) {
    for (const [skill, score] of Object.entries(session.skillMetrics!)) {
      const arr = skillMap.get(skill) ?? [];
      arr.push(score);
      skillMap.set(skill, arr);
    }
  }

  const trends: SkillTrend[] = [];
  for (const [skill, scores] of skillMap.entries()) {
    if (scores.length < 2) continue;
    const earliest = scores[0]!;
    const latest = scores[scores.length - 1]!;
    const delta = latest - earliest;
    const isPlateaued = Math.abs(delta) < plateauThreshold;
    trends.push({ skill, scores, latest, earliest, delta, isPlateaued });
  }

  return trends;
}

function buildRecommendation(
  agent: JarvisAgentDoc,
  trends: SkillTrend[],
  sessionCount: number
): AgentRecommendation {
  if (sessionCount < 3) {
    return {
      action: 'insufficient_data',
      reason: `Only ${sessionCount} completed sessions — need at least 3 to detect plateaus.`,
    };
  }

  const plateaued = trends.filter(t => t.isPlateaued);
  const progressing = trends.filter(t => !t.isPlateaued && t.delta > 0);

  if (plateaued.length === 0) {
    return {
      action: 'none',
      reason: `${progressing.length} skill(s) improving. No plateau detected.`,
    };
  }

  const avgLatest =
    plateaued.length > 0 ? plateaued.reduce((s, t) => s + t.latest, 0) / plateaued.length : 0;

  const currentLevel =
    ((agent as unknown as Record<string, unknown>)['difficultyLevel'] as string) ?? 'intermediate';

  if (avgLatest >= 0.75 && currentLevel !== 'advanced') {
    return {
      action: 'increase_difficulty',
      currentLevel,
      reason: `${plateaued.map(t => t.skill).join(', ')} plateaued at high scores (avg ${(avgLatest * 100).toFixed(0)}%). User may have outgrown current difficulty.`,
    };
  }

  return {
    action: 'supplementary_agent',
    suggestedRole: 'specialist',
    reason: `${plateaued.map(t => t.skill).join(', ')} stagnant despite ${sessionCount} sessions. A specialist agent targeting these skills may break the plateau.`,
  };
}

// ── Step 3: ProgressReportAgent ───────────────────────────────────────────────

function assembleProgressReport(
  runId: string,
  lookbackSessions: number,
  plateauThreshold: number,
  analyses: AgentProgressAnalysis[]
): ProgressAnalystReport {
  const agentsWithPlateau = analyses.filter(a => a.plateauedSkills.length > 0).length;
  const agentsProgressing = analyses.filter(
    a => a.plateauedSkills.length === 0 && a.recommendation.action !== 'insufficient_data'
  ).length;

  const summary =
    analyses.length === 0
      ? 'No agents found to analyze.'
      : `${agentsWithPlateau}/${analyses.length} agents show skill plateaus. ${agentsProgressing} progressing normally.`;

  return {
    runId,
    productId: 'jarvisjr',
    lookbackSessions,
    plateauThreshold,
    agentsAnalyzed: analyses.length,
    agentsWithPlateau,
    agentsProgressing,
    perAgent: analyses,
    summary,
    generatedAt: new Date().toISOString(),
  };
}

// ── Pipeline runner ────────────────────────────────────────────────────────────

async function runProgressAnalystPipeline(
  lookbackSessions: number,
  plateauThreshold: number,
  req: McpToolRequest
): Promise<ProgressAnalystReport> {
  const runId = randomUUID();
  const opts = { token: req.headers.authorization?.slice(7), requestId: req.id };

  req.log.info(
    { runId, stepId: 'collect', lookbackSessions },
    'SessionMetricsCollectorAgent start'
  );
  const agentsResult = await jarvisAgentsList({ limit: 50 }, opts).catch(() => ({
    agents: [] as JarvisAgentDoc[],
    total: 0,
  }));
  const collected = await Promise.all(
    agentsResult.agents.map(agent => collectAgentMetrics(agent, lookbackSessions, opts))
  );
  req.log.info(
    { runId, stepId: 'collect', agentCount: collected.length },
    'SessionMetricsCollectorAgent done'
  );

  req.log.info(
    { runId, stepId: 'plateau', agentCount: collected.length },
    'PlateauDetectorAgent start'
  );
  const analyses: AgentProgressAnalysis[] = collected.map(({ agent, sessions }) => {
    const trends = detectPlateaus(sessions, plateauThreshold);
    const plateauedSkills = trends.filter(t => t.isPlateaued).map(t => t.skill);
    const recommendation = buildRecommendation(
      agent,
      trends,
      sessions.filter(s => s.status === 'completed').length
    );
    return {
      agentId: agent.id,
      agentName: agent.name,
      sessionsAnalyzed: sessions.length,
      skills: trends,
      plateauedSkills,
      recommendation,
    };
  });
  req.log.info(
    {
      runId,
      stepId: 'plateau',
      plateauCount: analyses.filter(a => a.plateauedSkills.length > 0).length,
    },
    'PlateauDetectorAgent done'
  );

  req.log.info({ runId, stepId: 'report' }, 'ProgressReportAgent start');
  const report = assembleProgressReport(runId, lookbackSessions, plateauThreshold, analyses);
  req.log.info({ runId, stepId: 'report', summary: report.summary }, 'ProgressReportAgent done');

  return report;
}

// ── MCP tool registration ─────────────────────────────────────────────────────

registerTool({
  name: 'jarvis.progress.analyze',
  description:
    'A2A pipeline: analyzes skill progression across all JarvisJr coaching agents. Collects skillMetrics from recent sessions, detects stagnation/plateaus, and recommends difficulty increases or supplementary agents. Returns a per-agent report with skill trend deltas and actionable recommendations. Requires admin role.',
  requiredRole: 'admin',
  inputSchema: z.object({
    lookbackSessions: z.coerce
      .number()
      .int()
      .min(3)
      .max(50)
      .default(10)
      .describe('Number of most recent sessions to analyze per agent (default 10)'),
    plateauThreshold: z.coerce
      .number()
      .min(0)
      .max(0.5)
      .default(0.05)
      .describe('Max skill score delta to classify as plateaued (default 0.05 = 5% change)'),
  }),
  async execute(args, req) {
    return runProgressAnalystPipeline(args.lookbackSessions, args.plateauThreshold, req);
  },
});
