import { NextRequest, NextResponse } from "next/server";
import { z } from "zod";
import { Prisma } from "@prisma/client";
import { getCurrentUser } from "@/lib/auth";
import { prisma } from "@/lib/prisma";

// Schema now supports creating empty workouts (just date) or with sets
const createWorkoutSchema = z.object({
  name: z.string().optional(),
  notes: z.string().optional(),
  durationMinutes: z.number().int().positive().optional(),
  difficulty: z.number().int().min(1).max(10).optional(),
  caloriesBurned: z.number().int().positive().optional(),
  date: z.string().optional(), // ISO date string or date-only string
  sets: z
    .array(
      z.object({
        exerciseId: z.string(),
        setNumber: z.number().int().positive(),
        reps: z.number().int().positive().optional(),
        weight: z.number().positive().optional(),
        weightUnit: z.string().default("lbs"),
        rpe: z.number().int().min(1).max(10).optional(),
        durationSeconds: z.number().int().positive().optional(),
        distance: z.number().positive().optional(),
        distanceUnit: z.string().optional(),
        calories: z.number().int().positive().optional(),
        customMetrics: z.record(z.string()).optional(),
        notes: z.string().optional(),
      })
    )
    .optional()
    .default([]),
});

// GET: List workouts with search/date filters
export async function GET(request: NextRequest) {
  try {
    const user = await getCurrentUser();
    if (!user) {
      return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
    }

    const searchParams = request.nextUrl.searchParams;
    const query = searchParams.get("q");
    const dateFrom = searchParams.get("dateFrom");
    const dateTo = searchParams.get("dateTo");
    const limit = Math.min(parseInt(searchParams.get("limit") || "50"), 100);
    const offset = parseInt(searchParams.get("offset") || "0");

    const where: Prisma.WorkoutWhereInput = {
      userId: user.id,
      deletedAt: null,
    };

    if (query) {
      where.name = { contains: query };
    }

    if (dateFrom || dateTo) {
      const dateFilter: Prisma.DateTimeFilter = {};
      if (dateFrom) dateFilter.gte = new Date(dateFrom);
      if (dateTo) {
        const toDate = new Date(dateTo);
        toDate.setHours(23, 59, 59, 999);
        dateFilter.lte = toDate;
      }
      where.date = dateFilter;
    }

    const [workouts, total] = await Promise.all([
      prisma.workout.findMany({
        where,
        include: {
          setLogs: {
            include: {
              exercise: true,
            },
            orderBy: {
              setNumber: "asc",
            },
          },
        },
        orderBy: {
          date: "desc",
        },
        take: limit,
        skip: offset,
      }),
      prisma.workout.count({ where }),
    ]);

    return NextResponse.json({
      data: workouts,
      meta: {
        total,
        limit,
        offset,
        hasMore: offset + limit < total,
      },
    });
  } catch (error) {
    console.error("Failed to fetch workouts:", error);
    return NextResponse.json(
      { error: "Failed to fetch workouts" },
      { status: 500 }
    );
  }
}

// POST: Create workout (can be empty or with sets)
export async function POST(request: NextRequest) {
  try {
    const user = await getCurrentUser();
    if (!user) {
      return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
    }

    const body = await request.json();
    const validated = createWorkoutSchema.parse(body);

    const workoutDate = validated.date ? new Date(validated.date) : new Date();

    const createData: Prisma.WorkoutCreateInput = {
      user: { connect: { id: user.id } },
      name: validated.name || null,
      notes: validated.notes,
      durationMinutes: validated.durationMinutes,
      difficulty: validated.difficulty,
      caloriesBurned: validated.caloriesBurned,
      date: workoutDate,
      setLogs:
        validated.sets.length > 0
          ? {
              create: validated.sets.map((set) => ({
                exercise: { connect: { id: set.exerciseId } },
                setNumber: set.setNumber,
                reps: set.reps,
                weight: set.weight,
                weightUnit: set.weightUnit,
                rpe: set.rpe,
                durationSeconds: set.durationSeconds,
                distance: set.distance,
                distanceUnit: set.distanceUnit,
                calories: set.calories,
                customMetrics:
                  set.customMetrics && Object.keys(set.customMetrics).length > 0
                    ? JSON.stringify(set.customMetrics)
                    : undefined,
                notes: set.notes,
              })),
            }
          : undefined,
    };

    const includeOpts = {
      setLogs: {
        include: { exercise: true },
        orderBy: { setNumber: "asc" as const },
      },
    };

    const workout = await prisma.workout.create({ data: createData, include: includeOpts });

    return NextResponse.json(workout, { status: 201 });
  } catch (error) {
    if (error instanceof z.ZodError) {
      return NextResponse.json(
        { error: "Invalid request data", details: error.errors },
        { status: 400 }
      );
    }

    console.error("Failed to create workout:", error);
    return NextResponse.json(
      { error: "Failed to create workout" },
      { status: 500 }
    );
  }
}
