/**
 * Backend API Sketch — Pipo Fastify Server
 *
 * This file defines the API surface the Fitbit companion talks to.
 * It is a DESIGN DOCUMENT, not running code. Copy into Pipo backend
 * and implement with real Fastify + Hevy API client.
 *
 * Endpoints:
 *   GET  /api/workout-plan/:userId          — fetch today's routine
 *   POST /api/live-workout/events            — receive watch events
 *   POST /api/workout/complete               — finalize & POST to Hevy
 *   GET  /api/workout/:id/status             — poll sync status
 *
 * Auth: Hevy API key per user, stored in backend only.
 *       Fitbit companion sends userId (from Fitbit settings),
 *       never sees the Hevy key.
 */

// ─── Types (shared between companion ↔ backend) ─────────────────────

/** Sent by watch → companion → backend on each set completion */
export interface SetCompleteEvent {
  eventId: string;
  type: 'SET_COMPLETE';
  userId: string;
  routineId: string;
  exerciseIndex: number;
  setIndex: number;
  exerciseTemplateId: string;
  weightKg: number;
  reps: number;
  rir: number;
  timestamp: string;
}

export interface SkipSetEvent {
  eventId: string;
  type: 'SKIP_SET';
  userId: string;
  exerciseIndex: number;
  setIndex: number;
  timestamp: string;
}

export interface FinishWorkoutEvent {
  eventId: string;
  type: 'FINISH_WORKOUT';
  userId: string;
  startedAt: string;
  endedAt: string;
  timestamp: string;
}

export type WorkoutEvent = SetCompleteEvent | SkipSetEvent | FinishWorkoutEvent;

// ─── API Contracts ───────────────────────────────────────────────────

/**
 * GET /api/workout-plan/:userId
 *
 * Returns the user's active Hevy routine transformed into Fitbit-friendly format.
 * Cached for 1h in backend. Companion calls this on app open + pull-to-refresh.
 */
export interface WorkoutPlanResponse {
  ok: true;
  data: {
    routineId: string;
    routineName: string;
    exercises: {
      templateId: string;
      name: string;
      type: 'strength' | 'cardio' | 'other';
      sets: {
        index: number;
        targetWeightKg: number | null;
        targetReps: string;
        targetRir: number | null;
      }[];
      notes: string | null;
    }[];
    fetchedAt: string;
  };
}

/**
 * POST /api/live-workout/events
 *
 * Body: { userId, events: WorkoutEvent[] }
 *
 * Backend applies events in order to in-memory session.
 * Idempotent via eventId. Returns next exercise/set hints.
 */
export interface LiveWorkoutEventsResponse {
  ok: true;
  accepted: number;           // number of new events accepted
  nextSet: {                  // null if workout complete
    exerciseIndex: number;
    setIndex: number;
    targetWeightKg: number | null;
    targetReps: string;
    targetRir: number | null;
    exerciseName: string;
  } | null;
  workoutComplete: boolean;
}

export interface LiveWorkoutEventsError {
  ok: false;
  error: string;
  code: 'SESSION_NOT_FOUND' | 'INVALID_EVENT' | 'SERVER_ERROR';
}

/**
 * POST /api/workout/complete
 *
 * Called by companion when all sets are logged. Backend builds Hevy payload
 * and POSTs to Hevy API. Returns Hevy workout ID.
 *
 * Body: { userId, routineId, startedAt, endedAt }
 *
 * Backend also accepts full set data as fallback if events were missed.
 */
export interface WorkoutCompleteResponse {
  ok: true;
  hevyWorkoutId: string;
  hevyResponse: unknown; // raw Hevy API response for debugging
}

export interface WorkoutCompleteError {
  ok: false;
  error: string;
  code: 'HEVY_API_ERROR' | 'PAYLOAD_INVALID' | 'SESSION_NOT_FOUND' | 'SERVER_ERROR';
  retryable: boolean;
}

/**
 * GET /api/workout/:hevyWorkoutId/status
 *
 * Poll endpoint for sync verification. Returns Hevy workout details.
 */
export interface WorkoutStatusResponse {
  ok: true;
  hevyWorkoutId: string;
  hevyTitle: string;
  exerciseCount: number;
  setCount: number;
  createdAt: string;
}

// ─── Backend In-Memory Session Structure ─────────────────────────────

/**
 * Backend keeps a Map<userId, ActiveSession>.
 * Session is created on first SET_COMPLETE event,
 * destroyed after successful Hevy POST (or TTL expiry ~30 min idle).
 */
export interface ActiveSession {
  userId: string;
  routineId: string;
  sessionId: string;
  startedAt: string;
  lastEventAt: string;
  events: WorkoutEvent[];
  eventIds: Set<string>;       // for idempotency
  planSnapshot: WorkoutPlanResponse['data'];
  hevyWorkoutId: string | null;
  state: 'active' | 'finalizing' | 'synced' | 'error';
}

// ─── Fastify Route Skeleton ──────────────────────────────────────────

/*
// Copy this into Pipo backend routes/hevy-companion.ts

import { FastifyInstance, FastifyRequest, FastifyReply } from 'fastify';

export default async function hevyCompanionRoutes(fastify: FastifyInstance) {

  // GET /api/workout-plan/:userId
  fastify.get('/api/workout-plan/:userId', async (req: FastifyRequest<{
    Params: { userId: string }
  }>, reply: FastifyReply) => {
    const { userId } = req.params;
    // 1. Look up Hevy API key for userId
    // 2. GET /v1/routines → find active routine
    // 3. GET /v1/routines/:id → transform to WorkoutPlanResponse
    // 4. Cache for 60s
    // 5. Return
    return reply.send({ ok: true, data: { ... } });
  });

  // POST /api/live-workout/events
  fastify.post('/api/live-workout/events', async (req: FastifyRequest<{
    Body: { userId: string; events: WorkoutEvent[] }
  }>, reply: FastifyReply) => {
    const { userId, events } = req.body;
    // 1. Get or create ActiveSession for userId
    // 2. Apply events (skip duplicates via eventId)
    // 3. Return nextSet hint or workoutComplete: true
    return reply.send({ ok: true, accepted: N, nextSet: {...}, workoutComplete: false });
  });

  // POST /api/workout/complete
  fastify.post('/api/workout/complete', async (req: FastifyRequest<{
    Body: { userId: string; routineId: string; startedAt: string; endedAt: string }
  }>, reply: FastifyReply) => {
    const { userId, routineId, startedAt, endedAt } = req.body;
    // 1. Load ActiveSession for userId
    // 2. Build HevyWorkoutPayload from session events
    // 3. POST /v1/workouts to Hevy API
    // 4. Update session state → 'synced'
    // 5. Return hevyWorkoutId
    return reply.send({ ok: true, hevyWorkoutId: '...', hevyResponse: {...} });
  });

  // GET /api/workout/:id/status
  fastify.get('/api/workout/:id/status', async (req: FastifyRequest<{
    Params: { id: string }
  }>, reply: FastifyReply) => {
    const { id } = req.params;
    // 1. GET /v1/workouts/:id from Hevy
    // 2. Return summary
    return reply.send({ ok: true, hevyWorkoutId: id, ... });
  });
}
*/

// ─── Hevy API Payload Builder (server-side) ──────────────────────────

import type { SetCompleteEvent, SkipSetEvent } from './backend-api-sketch' ; // self-ref for doc

/**
 * Builds the Hevy POST /v1/workouts payload from accumulated session events.
 * Uses planSnapshot for exercise_template_id mapping.
 */
export function buildHevyWorkoutPayload(
  session: ActiveSession,
): {
  title: string;
  description: string;
  start_time: string;
  end_time: string;
  is_private: boolean;
  exercises: {
    exercise_template_id: string;
    notes?: string;
    sets: {
      type: 'normal' | 'warmup' | 'dropset' | 'failure';
      weight_kg: number;
      reps: number;
      rpe: number | null;
    }[];
  }[];
} {
  // Group events by exercise
  const exerciseMap = new Map<number, { templateId: string; name: string; sets: { weightKg: number; reps: number; rir: number }[] }>();

  for (const event of session.events) {
    if (event.type !== 'SET_COMPLETE') continue;

    const { exerciseIndex, exerciseTemplateId, weightKg, reps, rir } = event;
    if (!exerciseMap.has(exerciseIndex)) {
      const ex = session.planSnapshot.exercises[exerciseIndex];
      exerciseMap.set(exerciseIndex, {
        templateId: exerciseTemplateId,
        name: ex?.name ?? 'Unknown',
        sets: [],
      });
    }
    exerciseMap.get(exerciseIndex)!.sets.push({ weightKg, reps, rir });
  }

  const exercises = Array.from(exerciseMap.entries())
    .sort(([a], [b]) => a - b)
    .map(([, ex]) => ({
      exercise_template_id: ex.templateId,
      sets: ex.sets.map((s) => ({
        type: 'normal' as const,
        weight_kg: s.weightKg,
        reps: s.reps,
        rpe: s.rir !== undefined && s.rir !== null ? 10 - s.rir : null,
      })),
    }));

  return {
    title: session.planSnapshot.routineName || 'Fitbit Workout',
    description: `Completed via Hevy Companion (Fitbit Sense 2)`,
    start_time: session.startedAt,
    end_time: session.events[session.events.length - 1]?.timestamp ?? session.lastEventAt,
    is_private: false,
    exercises,
  };
}
