import { NextResponse } from "next/server";
import { getDatabase } from "@/lib/database";
import { buildAIContext } from "@/lib/ai/ai-context";
import { buildEnhancedPrompt, buildBasicPrompt } from "@/lib/ai/prompt-builder";
import log from "@/lib/logger";

export async function POST(req: Request) {
  try {
    const { userId, useExternalModel, modelProvider } = await req.json();

    if (!userId) {
      return NextResponse.json(
        { error: "User ID is required" },
        { status: 400 },
      );
    }

    log.debug("Generating recommendation for user", {
      userId,
      modelProvider,
      useExternalModel,
    });

    const db = await getDatabase();

    // Fetch fitness profile
    const profile = await db.getFitnessProfileByUserId(userId);

    if (!profile) {
      log.error("Fitness profile not found", undefined, { userId });
      return NextResponse.json(
        { error: "Fitness profile not found for this user" },
        { status: 404 },
      );
    }

    log.debug("Fitness profile found", { profileId: profile.id });

    // Build AI context with goals and recommendations
    let prompt: string;
    try {
      const context = await buildAIContext(userId);
      prompt = buildEnhancedPrompt(context);
      log.debug("Using enhanced AI context with goals and history");
    } catch (error) {
      // Fallback to basic prompt if context building fails
      log.warn("Failed to build AI context, using basic prompt", {
        error: error instanceof Error ? error.message : String(error),
      });
      prompt = buildBasicPrompt(profile);
    }

    let parsedResponse;

    // Determine which AI provider to use
    const provider =
      modelProvider || (useExternalModel ? "deepseek" : "ollama");

    if (provider === "openai") {
      // Use OpenAI
      const openaiApiKey = process.env.OPENAI_API_KEY;

      if (!openaiApiKey) {
        return NextResponse.json(
          { error: "OpenAI API key not configured" },
          { status: 500 },
        );
      }

      log.debug("Using OpenAI model", { userId });

      const openaiResponse = await fetch(
        "https://api.openai.com/v1/chat/completions",
        {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${openaiApiKey}`,
          },
          body: JSON.stringify({
            model: "gpt-4o-mini",
            messages: [
              {
                role: "system",
                content:
                  'You are a professional fitness trainer and nutritionist. Always respond with valid JSON only, no markdown or code blocks. The response must have this exact structure: {"recommendationText": "string", "activityPlan": "string", "dietPlan": "string"}',
              },
              {
                role: "user",
                content: prompt,
              },
            ],
            temperature: 0.7,
            max_tokens: 1500,
            response_format: { type: "json_object" },
          }),
        },
      );

      if (!openaiResponse.ok) {
        const errorText = await openaiResponse.text();
        log.error("OpenAI API request failed", new Error(errorText), {
          status: openaiResponse.status,
        });
        return NextResponse.json(
          { error: "Failed to generate recommendation from OpenAI" },
          { status: 500 },
        );
      }

      const openaiData = await openaiResponse.json();
      log.debug("Received OpenAI response", { openaiData });

      try {
        const content = openaiData.choices[0].message.content;
        parsedResponse = JSON.parse(content);
      } catch (e) {
        log.error("Failed to parse OpenAI response", e, {
          response: openaiData,
        });
        return NextResponse.json(
          { error: "Invalid response format from OpenAI" },
          { status: 500 },
        );
      }
    } else if (provider === "deepseek") {
      // Use DeepSeek AI
      const deepseekApiKey = process.env.DEEPSEEK_API_KEY;

      if (!deepseekApiKey) {
        return NextResponse.json(
          { error: "DeepSeek API key not configured" },
          { status: 500 },
        );
      }

      log.debug("Using DeepSeek AI model", { userId });

      const deepseekResponse = await fetch(
        "https://api.deepseek.com/v1/chat/completions",
        {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${deepseekApiKey}`,
          },
          body: JSON.stringify({
            model: "deepseek-chat",
            messages: [
              {
                role: "system",
                content:
                  "You are a professional fitness trainer and nutritionist. Always respond with valid JSON only, no markdown or code blocks.",
              },
              {
                role: "user",
                content: prompt,
              },
            ],
            temperature: 0.7,
            max_tokens: 1000,
          }),
        },
      );

      if (!deepseekResponse.ok) {
        const errorText = await deepseekResponse.text();
        log.error("DeepSeek API request failed", new Error(errorText), {
          status: deepseekResponse.status,
        });
        return NextResponse.json(
          { error: "Failed to generate recommendation from DeepSeek AI" },
          { status: 500 },
        );
      }

      const deepseekData = await deepseekResponse.json();
      log.debug("Received DeepSeek response", { deepseekData });

      try {
        const content = deepseekData.choices[0].message.content;
        let cleanResponse = content.trim();

        // Remove markdown code blocks if present
        if (cleanResponse.startsWith("```json")) {
          cleanResponse = cleanResponse
            .replace(/^```json\s*/, "")
            .replace(/\s*```$/, "");
        } else if (cleanResponse.startsWith("```")) {
          cleanResponse = cleanResponse
            .replace(/^```\s*/, "")
            .replace(/\s*```$/, "");
        }

        // Find the first '{' and last '}' to extract the JSON object
        const firstBrace = cleanResponse.indexOf("{");
        const lastBrace = cleanResponse.lastIndexOf("}");

        if (firstBrace !== -1 && lastBrace !== -1) {
          cleanResponse = cleanResponse.substring(firstBrace, lastBrace + 1);
        }

        parsedResponse = JSON.parse(cleanResponse);
      } catch (e) {
        log.error("Failed to parse DeepSeek response", e, {
          response: deepseekData,
        });
        return NextResponse.json(
          { error: "Invalid response format from DeepSeek AI" },
          { status: 500 },
        );
      }
    } else {
      // Use local Ollama
      log.debug("Using local Ollama model", { userId });

      const ollamaResponse = await fetch(
        "http://localhost:11434/api/generate",
        {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
          },
          body: JSON.stringify({
            model: "gemma3:latest",
            prompt: prompt,
            stream: false,
            format: "json",
          }),
        },
      );

      if (!ollamaResponse.ok) {
        const errorText = await ollamaResponse.text();
        log.error("Ollama API request failed", new Error(errorText), {
          status: ollamaResponse.status,
        });
        return NextResponse.json(
          { error: "Failed to generate recommendation from Ollama" },
          { status: 500 },
        );
      }

      const aiData = await ollamaResponse.json();
      log.debug("Received Ollama response", { response: aiData.response });

      try {
        let cleanResponse = aiData.response.trim();

        // Remove markdown code blocks if present
        if (cleanResponse.startsWith("```json")) {
          cleanResponse = cleanResponse
            .replace(/^```json\s*/, "")
            .replace(/\s*```$/, "");
        } else if (cleanResponse.startsWith("```")) {
          cleanResponse = cleanResponse
            .replace(/^```\s*/, "")
            .replace(/\s*```$/, "");
        }

        // Find the first '{' and last '}' to extract the JSON object
        const firstBrace = cleanResponse.indexOf("{");
        const lastBrace = cleanResponse.lastIndexOf("}");

        if (firstBrace !== -1 && lastBrace !== -1) {
          cleanResponse = cleanResponse.substring(firstBrace, lastBrace + 1);
        }

        parsedResponse = JSON.parse(cleanResponse);
      } catch (e) {
        log.error("Failed to parse Ollama response", e, {
          response: aiData.response,
        });
        return NextResponse.json(
          { error: "Invalid response format from Ollama" },
          { status: 500 },
        );
      }
    }

    // Save to database
    log.debug("Saving recommendation to database", {
      userId,
      profileId: profile.id,
      hasRecommendationText: !!parsedResponse.recommendationText,
      hasActivityPlan: !!parsedResponse.activityPlan,
      hasDietPlan: !!parsedResponse.dietPlan,
    });

    const recommendation = await db.createRecommendation({
      id: crypto.randomUUID(),
      userId,
      fitnessProfileId: profile.id,
      recommendationText: parsedResponse.recommendationText || "",
      activityPlan: parsedResponse.activityPlan || "",
      dietPlan: parsedResponse.dietPlan || "",
      status: "pending",
      generatedAt: new Date(),
      updatedAt: new Date(),
    });

    log.info("Recommendation generated successfully", {
      recommendationId: recommendation.id,
      userId,
    });

    // Return in standardized format
    return NextResponse.json({
      success: true,
      data: recommendation,
      meta: {
        timestamp: new Date().toISOString(),
        requestId: `req_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`,
      },
    });
  } catch (error) {
    log.error("Failed to generate recommendation", error, {
      errorMessage: error instanceof Error ? error.message : String(error),
      errorStack: error instanceof Error ? error.stack : undefined,
    });
    return NextResponse.json(
      { error: "Internal server error" },
      { status: 500 },
    );
  }
}
