/**
 * GoalCoachingAgent — A2A pipeline for PeakPulse activity goal recommendations.
 *
 * Agent roster (3 steps):
 *   1. SessionHistoryAgent  — fetch recent completed sessions, compute performance trends
 *   2. GoalAnalysisAgent    — compare trends against overall stats, identify improvement areas
 *   3. GoalReportAgent      — propose concrete next goals based on trend analysis
 *
 * MCP tools:
 *   peakpulse.goals.coach(activityType?, lookback?) — run pipeline
 */

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

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

interface PerformanceTrend {
  metric: string;
  unit: string;
  values: number[];
  average: number;
  recent: number;
  delta: number;
  trending: 'up' | 'down' | 'flat';
}

interface GoalSuggestion {
  metric: string;
  currentAverage: number;
  suggestedTarget: number;
  unit: string;
  rationale: string;
}

export interface GoalCoachingReport {
  runId: string;
  productId: 'peakpulse';
  activityType: string | null;
  sessionsAnalyzed: number;
  trends: PerformanceTrend[];
  suggestions: GoalSuggestion[];
  overallLevel: 'beginner' | 'intermediate' | 'advanced';
  summary: string;
  generatedAt: string;
}

// ── Step 1: SessionHistoryAgent ────────────────────────────────────────────────

async function fetchSessionHistory(
  activityType: string | null,
  lookback: number,
  opts: { token?: string; requestId?: string }
): Promise<PeakSessionDoc[]> {
  try {
    const result = await peakpulseSessionsList(
      { activityType: activityType ?? undefined, status: 'completed', limit: lookback },
      opts
    );
    return result.items.sort(
      (a: PeakSessionDoc, b: PeakSessionDoc) =>
        new Date(a.startTime).getTime() - new Date(b.startTime).getTime()
    );
  } catch {
    return [];
  }
}

// ── Step 2: GoalAnalysisAgent ─────────────────────────────────────────────────

function buildTrends(sessions: PeakSessionDoc[]): PerformanceTrend[] {
  if (sessions.length < 2) return [];

  const metricDefs: Array<{ key: keyof PeakSessionDoc; unit: string; label: string }> = [
    { key: 'durationSeconds', unit: 'min', label: 'duration' },
    { key: 'distanceMeters', unit: 'km', label: 'distance' },
    { key: 'elevationGainMeters', unit: 'm', label: 'elevation_gain' },
    { key: 'averageSpeedMps', unit: 'km/h', label: 'average_speed' },
  ];

  const trends: PerformanceTrend[] = [];

  for (const def of metricDefs) {
    const rawValues = sessions
      .map(s => s[def.key] as number | undefined)
      .filter((v): v is number => typeof v === 'number' && v > 0);

    if (rawValues.length < 2) continue;

    // Convert units
    const values =
      def.key === 'durationSeconds'
        ? rawValues.map(v => Math.round(v / 60))
        : def.key === 'distanceMeters'
          ? rawValues.map(v => Math.round(v / 100) / 10)
          : def.key === 'averageSpeedMps'
            ? rawValues.map(v => Math.round(v * 36) / 10)
            : rawValues;

    const average = values.reduce((s, v) => s + v, 0) / values.length;
    const recent = values[values.length - 1]!;
    const delta = recent - (values[0] ?? recent);
    const trending = delta > average * 0.05 ? 'up' : delta < -average * 0.05 ? 'down' : 'flat';

    trends.push({ metric: def.label, unit: def.unit, values, average, recent, delta, trending });
  }

  return trends;
}

function suggestGoals(
  trends: PerformanceTrend[],
  stats: Record<string, unknown>
): GoalSuggestion[] {
  const suggestions: GoalSuggestion[] = [];
  const totalSessions = typeof stats['totalSessions'] === 'number' ? stats['totalSessions'] : 0;

  for (const trend of trends) {
    let suggestedTarget = trend.average;
    let rationale = '';

    if (trend.trending === 'up') {
      // Already improving — push for 10% more
      suggestedTarget = Math.round(trend.recent * 1.1 * 10) / 10;
      rationale = `${trend.metric} is trending up (+${trend.delta.toFixed(1)} ${trend.unit}). Push to ${suggestedTarget} ${trend.unit}.`;
    } else if (trend.trending === 'flat' && totalSessions > 5) {
      // Plateau — target 15% improvement
      suggestedTarget = Math.round(trend.average * 1.15 * 10) / 10;
      rationale = `${trend.metric} has plateaued at avg ${trend.average.toFixed(1)} ${trend.unit}. Try targeting ${suggestedTarget} ${trend.unit} to break through.`;
    } else if (trend.trending === 'down') {
      // Declining — target returning to recent average
      suggestedTarget = Math.round(trend.average * 10) / 10;
      rationale = `${trend.metric} is declining. Focus on recovering to avg ${suggestedTarget} ${trend.unit}.`;
    }

    if (rationale) {
      suggestions.push({
        metric: trend.metric,
        currentAverage: Math.round(trend.average * 10) / 10,
        suggestedTarget,
        unit: trend.unit,
        rationale,
      });
    }
  }

  return suggestions;
}

function classifyLevel(sessions: PeakSessionDoc[]): 'beginner' | 'intermediate' | 'advanced' {
  if (sessions.length < 5) return 'beginner';
  const avgDuration = sessions.reduce((s, x) => s + (x.durationSeconds ?? 0), 0) / sessions.length;
  const avgDistance = sessions.reduce((s, x) => s + (x.distanceMeters ?? 0), 0) / sessions.length;
  if (avgDuration > 7200 && avgDistance > 15000) return 'advanced';
  if (avgDuration > 3600 || avgDistance > 8000) return 'intermediate';
  return 'beginner';
}

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

async function runGoalCoachingPipeline(
  activityType: string | null,
  lookback: number,
  req: McpToolRequest
): Promise<GoalCoachingReport> {
  const runId = randomUUID();
  const opts = { token: req.headers.authorization?.slice(7), requestId: req.id };

  req.log.info({ runId, stepId: 'history', activityType, lookback }, 'SessionHistoryAgent start');
  const sessions = await fetchSessionHistory(activityType, lookback, opts);
  req.log.info({ runId, stepId: 'history', count: sessions.length }, 'SessionHistoryAgent done');

  req.log.info({ runId, stepId: 'analyze' }, 'GoalAnalysisAgent start');
  const stats = await peakpulseGetStats(opts).catch(() => ({}) as Record<string, unknown>);
  const trends = buildTrends(sessions);
  const suggestions = suggestGoals(trends, stats as Record<string, unknown>);
  const overallLevel = classifyLevel(sessions);
  req.log.info(
    { runId, stepId: 'analyze', trendCount: trends.length, suggestionCount: suggestions.length },
    'GoalAnalysisAgent done'
  );

  req.log.info({ runId, stepId: 'report' }, 'GoalReportAgent start');
  const summary =
    sessions.length < 2
      ? 'Insufficient session history for goal coaching. Complete at least 2 sessions first.'
      : `Analyzed ${sessions.length} ${activityType ?? 'activity'} session(s). Level: ${overallLevel}. ${suggestions.length} goal suggestion(s) generated.`;

  req.log.info({ runId, stepId: 'report', summary }, 'GoalReportAgent done');

  return {
    runId,
    productId: 'peakpulse',
    activityType,
    sessionsAnalyzed: sessions.length,
    trends,
    suggestions,
    overallLevel,
    summary,
    generatedAt: new Date().toISOString(),
  };
}

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

registerTool({
  name: 'peakpulse.goals.coach',
  description:
    'A2A pipeline: analyzes PeakPulse session history to identify performance trends (duration, distance, elevation, speed) and proposes concrete next goals. Classifies user as beginner/intermediate/advanced. Optionally filter by activityType (hiking/skiing/cycling/running). Requires admin role.',
  requiredRole: 'admin',
  inputSchema: z.object({
    activityType: z
      .enum(['hiking', 'skiing', 'cycling', 'running'])
      .optional()
      .describe('Filter sessions by activity type (omit for all types)'),
    lookback: z.coerce
      .number()
      .int()
      .min(3)
      .max(50)
      .default(15)
      .describe('Number of recent sessions to analyze (default 15)'),
  }),
  async execute(args, req) {
    return runGoalCoachingPipeline(args.activityType ?? null, args.lookback, req);
  },
});
