/**
 * SkiRunAnalystAgent — A2A pipeline for PeakPulse ski session analysis.
 *
 * Agent roster (3 steps):
 *   1. SkiSessionCollectorAgent — fetch completed skiing sessions with skiMetrics
 *   2. RunQualityAnalystAgent   — compute per-session ski metrics, detect anomalies
 *   3. SkiReportAgent           — trend analysis + anomaly flags + improvement suggestions
 *
 * MCP tools:
 *   peakpulse.ski.analyze(lookback?) — run pipeline on recent ski sessions
 */

import { randomUUID } from 'node:crypto';
import { z } from 'zod';
import { registerTool } from '../tools/registry.js';
import type { McpToolRequest } from '../tools/types.js';
import { peakpulseSessionsList, type PeakSessionDoc } from '../../lib/peakpulse-client.js';

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

interface SkiSessionMetrics {
  sessionId: string;
  date: string;
  runCount: number;
  verticalDescentMeters: number;
  liftTimeSeconds: number;
  skiTimeSeconds: number;
  runDensity: number;
  verticalPerRun: number;
  skiToLiftRatio: number;
}

interface SkiAnomaly {
  sessionId: string;
  date: string;
  anomalyType: 'low_run_density' | 'high_lift_ratio' | 'short_session' | 'vertical_drop';
  description: string;
}

export interface SkiRunAnalystReport {
  runId: string;
  productId: 'peakpulse';
  sessionsAnalyzed: number;
  avgRunCount: number;
  avgVerticalDescentMeters: number;
  avgSkiToLiftRatio: number;
  sessionMetrics: SkiSessionMetrics[];
  anomalies: SkiAnomaly[];
  summary: string;
  generatedAt: string;
}

// ── Step 1: SkiSessionCollectorAgent ──────────────────────────────────────────

async function collectSkiSessions(
  lookback: number,
  opts: { token?: string; requestId?: string }
): Promise<PeakSessionDoc[]> {
  try {
    const result = await peakpulseSessionsList(
      { activityType: 'skiing', status: 'completed', limit: lookback },
      opts
    );
    return result.items.filter(s => s.skiMetrics !== undefined);
  } catch {
    return [];
  }
}

// ── Step 2: RunQualityAnalystAgent ────────────────────────────────────────────

function analyzeSession(session: PeakSessionDoc): SkiSessionMetrics {
  const ski = session.skiMetrics!;
  const runCount = ski.runCount ?? 0;
  const verticalDescentMeters = ski.verticalDescentMeters ?? 0;
  const liftTimeSeconds = ski.liftTimeSeconds ?? 0;
  const skiTimeSeconds = ski.skiTimeSeconds ?? 1;

  const runDensity = skiTimeSeconds > 0 ? runCount / (skiTimeSeconds / 3600) : 0;
  const verticalPerRun = runCount > 0 ? verticalDescentMeters / runCount : 0;
  const skiToLiftRatio = liftTimeSeconds > 0 ? skiTimeSeconds / liftTimeSeconds : 0;

  return {
    sessionId: session.id,
    date: session.startTime,
    runCount,
    verticalDescentMeters,
    liftTimeSeconds,
    skiTimeSeconds,
    runDensity: Math.round(runDensity * 10) / 10,
    verticalPerRun: Math.round(verticalPerRun),
    skiToLiftRatio: Math.round(skiToLiftRatio * 100) / 100,
  };
}

function detectAnomalies(
  metrics: SkiSessionMetrics[],
  avgRunDensity: number,
  avgVertical: number
): SkiAnomaly[] {
  const anomalies: SkiAnomaly[] = [];

  for (const m of metrics) {
    if (m.runDensity < avgRunDensity * 0.5 && m.runCount > 0) {
      anomalies.push({
        sessionId: m.sessionId,
        date: m.date,
        anomalyType: 'low_run_density',
        description: `${m.runDensity.toFixed(1)} runs/hour vs avg ${avgRunDensity.toFixed(1)} — possible injury, poor conditions, or excessive queueing.`,
      });
    }
    if (m.skiToLiftRatio < 0.5 && m.liftTimeSeconds > 1800) {
      anomalies.push({
        sessionId: m.sessionId,
        date: m.date,
        anomalyType: 'high_lift_ratio',
        description: `Ski-to-lift ratio ${m.skiToLiftRatio.toFixed(2)} is below 0.5 — more time on lifts than skiing.`,
      });
    }
    if (m.skiTimeSeconds < 3600 && m.runCount < 5) {
      anomalies.push({
        sessionId: m.sessionId,
        date: m.date,
        anomalyType: 'short_session',
        description: `Only ${m.runCount} runs in ${Math.round(m.skiTimeSeconds / 60)} ski minutes — unusually short session.`,
      });
    }
    if (m.verticalPerRun < avgVertical * 0.5 && avgVertical > 0) {
      anomalies.push({
        sessionId: m.sessionId,
        date: m.date,
        anomalyType: 'vertical_drop',
        description: `${m.verticalPerRun}m vertical per run vs avg ${Math.round(avgVertical)}m — user may be avoiding challenging terrain.`,
      });
    }
  }

  return anomalies;
}

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

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

  req.log.info({ runId, stepId: 'collect', lookback }, 'SkiSessionCollectorAgent start');
  const sessions = await collectSkiSessions(lookback, opts);
  req.log.info(
    { runId, stepId: 'collect', count: sessions.length },
    'SkiSessionCollectorAgent done'
  );

  req.log.info({ runId, stepId: 'analyze' }, 'RunQualityAnalystAgent start');
  const sessionMetrics = sessions.map(analyzeSession);
  const avgRunCount =
    sessionMetrics.reduce((s, m) => s + m.runCount, 0) / (sessionMetrics.length || 1);
  const avgVerticalDescentMeters =
    sessionMetrics.reduce((s, m) => s + m.verticalDescentMeters, 0) / (sessionMetrics.length || 1);
  const avgSkiToLiftRatio =
    sessionMetrics.reduce((s, m) => s + m.skiToLiftRatio, 0) / (sessionMetrics.length || 1);
  const avgRunDensity =
    sessionMetrics.reduce((s, m) => s + m.runDensity, 0) / (sessionMetrics.length || 1);
  const avgVerticalPerRun =
    sessionMetrics.reduce((s, m) => s + m.verticalPerRun, 0) / (sessionMetrics.length || 1);
  const anomalies = detectAnomalies(sessionMetrics, avgRunDensity, avgVerticalPerRun);
  req.log.info(
    { runId, stepId: 'analyze', anomalyCount: anomalies.length },
    'RunQualityAnalystAgent done'
  );

  req.log.info({ runId, stepId: 'report' }, 'SkiReportAgent start');
  const summary =
    sessions.length === 0
      ? 'No completed skiing sessions with ski metrics found.'
      : `Analyzed ${sessions.length} ski session(s). Avg ${Math.round(avgRunCount)} runs/session, ${Math.round(avgVerticalDescentMeters)}m vertical. ${anomalies.length} anomaly(ies) flagged.`;
  req.log.info({ runId, stepId: 'report', summary }, 'SkiReportAgent done');

  return {
    runId,
    productId: 'peakpulse',
    sessionsAnalyzed: sessions.length,
    avgRunCount: Math.round(avgRunCount * 10) / 10,
    avgVerticalDescentMeters: Math.round(avgVerticalDescentMeters),
    avgSkiToLiftRatio: Math.round(avgSkiToLiftRatio * 100) / 100,
    sessionMetrics,
    anomalies,
    summary,
    generatedAt: new Date().toISOString(),
  };
}

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

registerTool({
  name: 'peakpulse.ski.analyze',
  description:
    'A2A pipeline: analyzes PeakPulse skiing sessions using SkiMetrics data (runCount, verticalDescent, liftTime, skiTime). Computes run density, vertical per run, ski-to-lift ratio, and flags anomalies (low density, high lift ratio, short session, vertical drop vs baseline). Requires admin role.',
  requiredRole: 'admin',
  inputSchema: z.object({
    lookback: z.coerce
      .number()
      .int()
      .min(2)
      .max(50)
      .default(20)
      .describe('Number of recent skiing sessions to analyze (default 20)'),
  }),
  async execute(args, req) {
    return runSkiRunAnalystPipeline(args.lookback, req);
  },
});
