/**
 * SafetyMonitorAgent — A2A pipeline for NomGap extended-fast safety checks.
 *
 * Agent roster (4 steps):
 *   1. FastStateInspectorAgent  — fetch active fasting session + elapsed hours
 *   2. ThresholdEvaluatorAgent  — pure eval: safe / caution / critical + pushType
 *   3. SafetyNotificationAgent  — fire push notification + log telemetry event
 *   4. ExtendedFastHandoffAgent — emit A2A handoff artifact when elapsedHours >= 72
 *
 * MCP tools:
 *   nomgap.safety.check(userId)          — run the full pipeline
 *   nomgap.safety.getThresholds()        — return the threshold table (no I/O)
 */

import { randomUUID } from 'node:crypto';
import { z } from 'zod';
import { registerTool } from '../tools/registry.js';
import type { McpToolRequest } from '../tools/types.js';
import {
  nomgapFastingSessionsList,
  nomgapPushFire,
  type FastingSessionDoc,
} from '../../lib/nomgap-client.js';

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

type SafetyLevel = 'safe' | 'caution' | 'critical';
type PushType = 'refeeding_reminder' | 'extended_fast_warning' | 'electrolyte_reminder' | null;

interface FastStateResult {
  sessionId: string;
  protocolId: string;
  startedAt: number;
  elapsedHours: number;
  targetHours: number;
  isActive: boolean;
}

interface ThresholdResult {
  safetyLevel: SafetyLevel;
  pushType: PushType;
  escalate: boolean;
  messageVariables: Record<string, string>;
}

interface NotificationResult {
  notified: boolean;
  pushType: PushType;
}

interface HandoffResult {
  handoffEmitted: boolean;
  handoffPayload?: {
    productId: 'nomgap';
    agentTarget: 'ExtendedFastDetectionAgent';
    userId: string;
    sessionId: string;
    elapsedHours: number;
    triggeredAt: string;
  };
}

export interface SafetyCheckResult {
  runId: string;
  userId: string;
  productId: 'nomgap';
  sessionId: string | null;
  elapsedHours: number;
  safetyLevel: SafetyLevel;
  actionsTaken: string[];
  handoff: HandoffResult | null;
  checkedAt: string;
}

// ── Threshold table ───────────────────────────────────────────────────────────

export const SAFETY_THRESHOLDS = [
  {
    minHours: 72,
    maxHours: Infinity,
    level: 'critical' as SafetyLevel,
    pushType: 'extended_fast_warning' as PushType,
    escalate: true,
  },
  {
    minHours: 48,
    maxHours: 72,
    level: 'critical' as SafetyLevel,
    pushType: 'refeeding_reminder' as PushType,
    escalate: false,
  },
  {
    minHours: 42,
    maxHours: 48,
    level: 'caution' as SafetyLevel,
    pushType: 'refeeding_reminder' as PushType,
    escalate: false,
  },
  {
    minHours: 24,
    maxHours: 42,
    level: 'caution' as SafetyLevel,
    pushType: 'electrolyte_reminder' as PushType,
    escalate: false,
  },
  {
    minHours: 0,
    maxHours: 24,
    level: 'safe' as SafetyLevel,
    pushType: null as PushType,
    escalate: false,
  },
];

// ── Step 1: FastStateInspectorAgent ──────────────────────────────────────────

async function inspectFastState(
  userId: string,
  opts: { token?: string; requestId?: string }
): Promise<FastStateResult | null> {
  const result = await nomgapFastingSessionsList(
    { status: 'active', limit: 1 },
    { token: opts.token, requestId: opts.requestId }
  );

  const session = result.items[0] as FastingSessionDoc | undefined;
  if (!session) return null;

  const startedAt = session.startedAt ?? new Date(session.createdAt).getTime();
  const elapsedMs = Date.now() - startedAt;
  const elapsedHours = elapsedMs / (1000 * 60 * 60);

  return {
    sessionId: session.id,
    protocolId: session.protocolId ?? 'unknown',
    startedAt,
    elapsedHours: Math.round(elapsedHours * 10) / 10,
    targetHours: session.targetDurationMs
      ? (session.targetDurationMs as number) / (1000 * 60 * 60)
      : 0,
    isActive: true,
  };
}

// ── Step 2: ThresholdEvaluatorAgent (pure — no I/O) ──────────────────────────

function evaluateThreshold(state: FastStateResult): ThresholdResult {
  const row =
    SAFETY_THRESHOLDS.find(
      t => state.elapsedHours >= t.minHours && state.elapsedHours < t.maxHours
    ) ?? SAFETY_THRESHOLDS[SAFETY_THRESHOLDS.length - 1];

  return {
    safetyLevel: row.level,
    pushType: row.pushType,
    escalate: row.escalate,
    messageVariables: {
      hours: String(Math.floor(state.elapsedHours)),
      protocolId: state.protocolId,
      refeedingTip: 'Start with small amounts of easily digestible foods.',
    },
  };
}

// ── Step 3: SafetyNotificationAgent ──────────────────────────────────────────

async function sendSafetyNotification(
  userId: string,
  threshold: ThresholdResult,
  sessionId: string,
  opts: { token?: string; requestId?: string }
): Promise<NotificationResult> {
  if (!threshold.pushType) return { notified: false, pushType: null };

  try {
    await nomgapPushFire(
      {
        type: threshold.pushType as Parameters<typeof nomgapPushFire>[0]['type'],
        userId,
        variables: threshold.messageVariables,
      },
      { token: opts.token, requestId: opts.requestId }
    );
    return { notified: true, pushType: threshold.pushType };
  } catch {
    return { notified: false, pushType: threshold.pushType };
  }
}

// ── Step 4: ExtendedFastHandoffAgent ─────────────────────────────────────────

function emitExtendedFastHandoff(
  userId: string,
  sessionId: string,
  elapsedHours: number
): HandoffResult {
  return {
    handoffEmitted: true,
    handoffPayload: {
      productId: 'nomgap',
      agentTarget: 'ExtendedFastDetectionAgent',
      userId,
      sessionId,
      elapsedHours,
      triggeredAt: new Date().toISOString(),
    },
  };
}

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

export async function runSafetyMonitorPipeline(
  userId: string,
  opts: { token?: string; requestId?: string }
): Promise<SafetyCheckResult> {
  const runId = `run_safety_${randomUUID().slice(0, 8)}`;
  const checkedAt = new Date().toISOString();
  const actionsTaken: string[] = [];

  // Step 1: inspect fast state
  const fastState = await inspectFastState(userId, opts).catch(() => null);

  if (!fastState) {
    return {
      runId,
      userId,
      productId: 'nomgap',
      sessionId: null,
      elapsedHours: 0,
      safetyLevel: 'safe',
      actionsTaken: ['no_active_session'],
      handoff: null,
      checkedAt,
    };
  }

  // Step 2: evaluate threshold (pure)
  const threshold = evaluateThreshold(fastState);
  actionsTaken.push(`threshold:${threshold.safetyLevel}`);

  // Step 3: send notification
  const notification = await sendSafetyNotification(userId, threshold, fastState.sessionId, opts);
  if (notification.notified) actionsTaken.push(`push:${notification.pushType}`);

  // Step 4: handoff for 72h+ fasts
  let handoff: HandoffResult | null = null;
  if (threshold.escalate) {
    handoff = emitExtendedFastHandoff(userId, fastState.sessionId, fastState.elapsedHours);
    actionsTaken.push('handoff:ExtendedFastDetectionAgent');
  }

  return {
    runId,
    userId,
    productId: 'nomgap',
    sessionId: fastState.sessionId,
    elapsedHours: fastState.elapsedHours,
    safetyLevel: threshold.safetyLevel,
    actionsTaken,
    handoff,
    checkedAt,
  };
}

// ── MCP tool: nomgap.safety.check ─────────────────────────────────────────────

registerTool({
  name: 'nomgap.safety.check',
  description: [
    'A2A safety pipeline for NomGap extended fasts.',
    "Fetches the user's active fasting session, evaluates against safety thresholds",
    '(safe <24h / caution 24-48h / critical 48h+), fires the appropriate push notification',
    '(electrolyte_reminder / refeeding_reminder / extended_fast_warning), and emits an',
    'A2A handoff artifact to ExtendedFastDetectionAgent for fasts ≥ 72 h.',
    'Returns SafetyCheckResult with safetyLevel, actionsTaken, and handoff payload.',
    'Requires admin role.',
  ].join(' '),
  requiredRole: 'admin',
  inputSchema: z.object({
    userId: z.string().min(1).describe('NomGap user ID to check'),
  }),
  async execute(args, req: McpToolRequest) {
    const token = req.headers.authorization?.slice(7);
    return runSafetyMonitorPipeline(args.userId, { token, requestId: req.id });
  },
});

// ── MCP tool: nomgap.safety.getThresholds ────────────────────────────────────

registerTool({
  name: 'nomgap.safety.getThresholds',
  description:
    'Returns the NomGap fasting safety threshold table: hours ranges, safety levels, push types, and escalation flags. Pure read — no I/O, no auth required beyond viewer role.',
  requiredRole: 'viewer',
  inputSchema: z.object({}),
  async execute() {
    return { thresholds: SAFETY_THRESHOLDS };
  },
});
