import { NextRequest, NextResponse } from 'next/server';
import { z } from 'zod';
import { getCurrentUser } from '@/lib/auth';
import { prisma } from '@/lib/prisma';
import { WORKOUT_OUTPUT_SHAPE, aiWorkoutSchema } from '@/lib/ai/workoutSchema';
import {
  buildHistorySummary,
  formatHistoryContext,
} from '@/lib/ai/historyContext';
import { buildWorkoutSystemPrompt } from '@/lib/ai/workoutPrompt';
import { kickoffGeneration } from '@/lib/ai/generationRunner';

/**
 * POST /api/ai/generate-workout
 *
 * Kicks off a background runner (kind="workout") that streams a single
 * day's workout suggestion, and returns the generation id. The caller
 * subscribes via GET /api/ai/generations/[id]/stream (SSE) — the same
 * spine as program generation.
 *
 * Body:
 *   { userInput: string, includeHistory?: boolean, priorWorkout?: AIWorkout }
 *
 * `priorWorkout` switches the prompt into REVISION mode: userInput is the
 * change instruction and the model re-emits the full revised workout.
 *
 * Response:
 *   201 { id: "...generationId..." }
 *   400 { error: "..." }
 */

const bodySchema = z.object({
  userInput: z.string().min(1),
  includeHistory: z.boolean().optional().default(false),
  // The current suggestion, when refining. Validated against the same
  // shape the model emits so we only ever feed it well-formed JSON.
  priorWorkout: aiWorkoutSchema.optional().nullable(),
});

export const dynamic = 'force-dynamic';

export async function POST(request: NextRequest) {
  const user = await getCurrentUser();
  if (!user) {
    return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
  }

  const body = await request.json().catch(() => ({}));
  const parsed = bodySchema.safeParse(body);
  if (!parsed.success) {
    return NextResponse.json(
      { error: 'Invalid body', details: parsed.error.errors },
      { status: 400 },
    );
  }

  const prefs = await prisma.userPreferences.findUnique({
    where: { userId: user.id },
  });
  if (!prefs?.aiProvider || !prefs?.aiModel) {
    return NextResponse.json(
      {
        error:
          'AI is not configured. Open Settings → AI integration and pick a provider + model.',
      },
      { status: 400 },
    );
  }

  const weightUnit = (prefs.defaultWeightUnit as 'lbs' | 'kg') || 'lbs';

  // Library for the prompt. We include each exercise's effective logging
  // unit (`defaultWeightUnit || "lbs"` — the exact unit the saved workout
  // will store, see WorkoutForm.buildPayload) so the model suggests the
  // weight NUMBER in that unit. Without this the model would assume the
  // user's global preferred unit, which diverges for per-exercise unit
  // overrides (e.g. kettlebells in kg) and silently mislabels the weight.
  const exercises = await prisma.exercise.findMany({
    where: { userId: user.id },
    select: {
      id: true,
      name: true,
      type: true,
      muscleGroups: true,
      defaultWeightUnit: true,
    },
  });
  const libraryJson = JSON.stringify(
    exercises.map((e) => ({
      id: e.id,
      name: e.name,
      type: e.type,
      unit: e.defaultWeightUnit || 'lbs',
      muscleGroups: (() => {
        try {
          return JSON.parse(e.muscleGroups);
        } catch {
          return [];
        }
      })(),
    })),
  );

  // History context if requested.
  let historyBlock = '';
  if (parsed.data.includeHistory) {
    const summary = await buildHistorySummary(prisma, user.id);
    historyBlock = formatHistoryContext(summary);
  }

  const isLocalModel = prefs.aiProvider === 'ollama';
  const priorWorkoutJson = parsed.data.priorWorkout
    ? JSON.stringify(parsed.data.priorWorkout)
    : undefined;

  const basePrompt = buildWorkoutSystemPrompt({
    weightUnit,
    hasHistoryContext: parsed.data.includeHistory,
    isLocalModel,
    priorWorkoutJson,
  });

  const systemPrompt = `${basePrompt}

# OUTPUT SHAPE

${WORKOUT_OUTPUT_SHAPE}

# LIBRARY (use these exerciseIds; do not invent ids)

${libraryJson}${historyBlock}`;

  const id = await kickoffGeneration({
    prisma,
    userId: user.id,
    kind: 'workout',
    templateId: null,
    templateName: priorWorkoutJson ? 'Workout (refine)' : 'Workout',
    userInput: parsed.data.userInput,
    systemPrompt,
    userPrompt: parsed.data.userInput,
    provider: prefs.aiProvider,
    model: prefs.aiModel,
    apiKey: prefs.aiApiKey,
    baseUrl: prefs.aiBaseUrl,
  });

  return NextResponse.json({ id }, { status: 201 });
}
