/**
 * NomGap MCP tools — nomgap.fasting.*, nomgap.push.*
 *
 * Backed by: nomgap-backend (port 4013).
 * All tools require admin role.
 */

import { z } from 'zod';
import { registerTool } from '../tools/registry.js';
import { config } from '../../lib/config.js';
import {
  nomgapFastingCreateSession,
  nomgapFastingSessionsList,
  nomgapFastingSessionGet,
  nomgapFastingGetStats,
  nomgapFastingGetWeeklyStats,
  nomgapProtocolsList,
  nomgapProtocolGet,
  nomgapSocialListGroupFasts,
  nomgapBodyStagesList,
  nomgapAutophagyConfidence,
  nomgapPushFire,
  nomgapPushGetStats,
  nomgapPushGetPending,
} from '../../lib/nomgap-client.js';
import type { McpToolRequest } from '../tools/types.js';

const tokenOf = (req: McpToolRequest) => req.headers.authorization?.slice(7);

// ── nomgap.fasting.sessions.list ──────────────────────────────────────────

registerTool({
  name: 'nomgap.fasting.sessions.list',
  description:
    'List fasting sessions for the authenticated user. Filter by status or date range. Requires admin role.',
  requiredRole: 'admin',
  inputSchema: z.object({
    status: z
      .enum(['active', 'completed', 'broken'])
      .optional()
      .describe('Filter by session status'),
    from: z.string().datetime().optional().describe('ISO 8601 start of date range'),
    to: z.string().datetime().optional().describe('ISO 8601 end of date range'),
    limit: z.coerce.number().min(1).max(config.QUERY_MAX_LIMIT).default(config.QUERY_DEFAULT_LIMIT),
    offset: z.coerce.number().min(0).default(0),
  }),
  async execute(args, req) {
    return nomgapFastingSessionsList(args, { token: tokenOf(req), requestId: req.id });
  },
});

// ── nomgap.fasting.stats ──────────────────────────────────────────────────

registerTool({
  name: 'nomgap.fasting.stats',
  description:
    'Get aggregated fasting stats for the authenticated user (streak, longestFast, completionRate, totalFasts). Requires admin role.',
  requiredRole: 'admin',
  inputSchema: z.object({}),
  async execute(_args, req) {
    return nomgapFastingGetStats({ token: tokenOf(req), requestId: req.id });
  },
});

// ── nomgap.fasting.stats.weekly ───────────────────────────────────────────

registerTool({
  name: 'nomgap.fasting.stats.weekly',
  description:
    "Get this week's fasting summary for the authenticated user (sessions, total hours, average duration). Requires admin role.",
  requiredRole: 'admin',
  inputSchema: z.object({}),
  async execute(_args, req) {
    return nomgapFastingGetWeeklyStats({ token: tokenOf(req), requestId: req.id });
  },
});

// ── nomgap.push.fire ──────────────────────────────────────────────────────

registerTool({
  name: 'nomgap.push.fire',
  description: [
    'Fire a push notification trigger for a NomGap user. One of 7 trigger types:',
    '  • streak_risk — user is at risk of losing their streak',
    '  • fast_milestone — fasting duration milestone reached',
    '  • stage_transition — entered a new metabolic stage (ketosis, autophagy…)',
    '  • social_invite — invited to a group fast',
    '  • weekly_digest — weekly summary push',
    '  • achievement_unlocked — badge or achievement earned',
    '  • refeeding_reminder — safety-critical refeeding guidance (48h+ fasts)',
    'Requires admin role.',
  ].join('\n'),
  requiredRole: 'admin',
  inputSchema: z.object({
    type: z
      .enum([
        'streak_risk',
        'fast_milestone',
        'stage_transition',
        'social_invite',
        'weekly_digest',
        'achievement_unlocked',
        'refeeding_reminder',
      ])
      .describe('Push trigger type'),
    userId: z.string().min(1).describe('Target user ID'),
    variables: z
      .record(z.string())
      .optional()
      .default({})
      .describe('Template variables for the notification message'),
    scheduledFor: z.string().datetime().optional().describe('ISO 8601 fire time (default: now)'),
  }),
  async execute(args, req) {
    return nomgapPushFire(
      {
        type: args.type,
        userId: args.userId,
        variables: args.variables,
        scheduledFor: args.scheduledFor,
      },
      { token: tokenOf(req), requestId: req.id }
    );
  },
});

// ── nomgap.push.stats ─────────────────────────────────────────────────────

registerTool({
  name: 'nomgap.push.stats',
  description:
    'Get push trigger delivery stats by type (sent, skipped, failed counts). Requires admin role.',
  requiredRole: 'admin',
  inputSchema: z.object({}),
  async execute(_args, req) {
    return nomgapPushGetStats({ token: tokenOf(req), requestId: req.id });
  },
});

// ── nomgap.protocols.list ──────────────────────────────────────────────────

registerTool({
  name: 'nomgap.protocols.list',
  description:
    'List all fasting protocols (built-in + user custom). Includes fastHours, eatHours, difficulty, and type. Requires admin role.',
  requiredRole: 'admin',
  inputSchema: z.object({}),
  async execute(_args, req) {
    return nomgapProtocolsList({ token: tokenOf(req), requestId: req.id });
  },
});

// ── nomgap.bodyStages.list ───────────────────────────────────────────────

registerTool({
  name: 'nomgap.bodyStages.list',
  description:
    'List all 6 fasting body stages (fed, early_fast, fasted, ketosis, deep_autophagy, extended) with hour thresholds and visualization metadata. Public endpoint — no auth needed.',
  requiredRole: 'admin',
  inputSchema: z.object({}),
  async execute(_args, req) {
    return nomgapBodyStagesList({ requestId: req.id });
  },
});

// ── nomgap.autophagyConfidence ─────────────────────────────────────────────────

registerTool({
  name: 'nomgap.autophagyConfidence',
  description: [
    'Calculate a personalised autophagy confidence score (0–100) given fasting duration and biometrics.',
    'Weights: duration 40%, last-meal carbs 20%, activity 15%, sleep 10%, completion history 10%, HRV 5%.',
    'Returns: confidence (0–100), label (unlikely/possible/likely/very_likely/near_certain), breakdown, currentStage.',
    'Public endpoint — no auth required on backend.',
  ].join(' '),
  requiredRole: 'admin',
  inputSchema: z.object({
    durationHours: z.coerce.number().min(0).describe('Hours elapsed since the fast started'),
    activityLevel: z
      .enum(['sedentary', 'light', 'moderate', 'active', 'very_active'])
      .describe('Physical activity level during the fast'),
    lastMealCarbs: z.coerce
      .number()
      .min(0)
      .optional()
      .describe('Grams of carbs in the last meal before the fast'),
    sleepHours: z.coerce
      .number()
      .min(0)
      .max(24)
      .optional()
      .describe('Hours of sleep the previous night'),
    completionHistory: z
      .object({
        totalFasts: z.coerce.number().min(0),
        completionRate: z.coerce.number().min(0).max(1),
      })
      .optional()
      .describe('Historical fasting stats (improves scoring accuracy)'),
    hrvData: z
      .object({
        restingHR: z.coerce.number().min(0).optional(),
        hrv: z.coerce.number().min(0).optional(),
      })
      .optional()
      .describe('Heart rate variability data from wearable'),
  }),
  async execute(args, req) {
    return nomgapAutophagyConfidence(args, { requestId: req.id });
  },
});

// ── nomgap.fasting.getSession ────────────────────────────────────────────

registerTool({
  name: 'nomgap.fasting.getSession',
  description:
    'Get a single fasting session by ID. Returns full session document including stage transitions, mood check-ins, water intake, and computed metrics. Requires admin role.',
  requiredRole: 'admin',
  inputSchema: z.object({
    sessionId: z.string().min(1).describe('Fasting session ID'),
  }),
  async execute(args, req) {
    return nomgapFastingSessionGet(args.sessionId, { token: tokenOf(req), requestId: req.id });
  },
});

// ── nomgap.fasting.createSession ────────────────────────────────────────────

registerTool({
  name: 'nomgap.fasting.createSession',
  description:
    'Start a new fasting session for the authenticated user with a given protocol. Returns the new session document including startedAt and targetDurationMs. Requires admin role.',
  requiredRole: 'admin',
  inputSchema: z.object({
    protocolId: z.string().min(1).describe('Protocol ID to use for this session'),
  }),
  async execute(args, req) {
    return nomgapFastingCreateSession(
      { protocolId: args.protocolId },
      { token: tokenOf(req), requestId: req.id }
    );
  },
});

// ── nomgap.protocols.get ─────────────────────────────────────────────────────

registerTool({
  name: 'nomgap.protocols.get',
  description:
    'Get a single fasting protocol by ID including its name, targetHours, description, steps, and default variables. Requires admin role.',
  requiredRole: 'admin',
  inputSchema: z.object({
    protocolId: z.string().min(1).describe('Fasting protocol ID'),
  }),
  async execute(args, req) {
    return nomgapProtocolGet(args.protocolId, { token: tokenOf(req), requestId: req.id });
  },
});

// ── nomgap.social.listGroupFasts ─────────────────────────────────────────────

registerTool({
  name: 'nomgap.social.listGroupFasts',
  description:
    'List group fasting sessions the authenticated user has participated in or created. Returns sessionId, memberCount, and status (active/completed/cancelled). Requires admin role.',
  requiredRole: 'admin',
  inputSchema: z.object({
    limit: z.coerce.number().min(1).max(config.QUERY_MAX_LIMIT).default(config.QUERY_DEFAULT_LIMIT),
    offset: z.coerce.number().min(0).default(0),
  }),
  async execute(args, req) {
    return nomgapSocialListGroupFasts(args, { token: tokenOf(req), requestId: req.id });
  },
});

// ── nomgap.push.pending ───────────────────────────────────────────────────

registerTool({
  name: 'nomgap.push.pending',
  description:
    'List push triggers that are pending delivery (scheduledAt <= now, status = pending). Useful for diagnosing delivery backlogs. Requires admin role.',
  requiredRole: 'admin',
  inputSchema: z.object({}),
  async execute(_args, req) {
    return nomgapPushGetPending({ token: tokenOf(req), requestId: req.id });
  },
});
