/**
 * Vercel Edge Function for LLM API Proxy
 *
 * This Edge Function proxies requests to the LLM provider while keeping
 * API keys secure on the server side. It implements the Edge Runtime for
 * fast cold starts (<3s).
 *
 * Runtime: Edge (required by architecture)
 */

import { NextRequest } from 'next/server';
import { createOpenAI } from '@ai-sdk/openai';
import { createOpenAICompatible } from '@ai-sdk/openai-compatible';
import { streamText, generateText } from 'ai';

// Edge Runtime is REQUIRED for this API route
export const runtime = 'edge';

/**
 * POST handler for LLM requests
 *
 * Expects JSON body with:
 * - prompt: The prompt to send to the LLM (legacy/simple mode)
 * - messages: Array of chat messages (standard mode)
 * - stream: Optional boolean to enable streaming (default: true)
 * - apiKey: Dynamic API key (BYOK)
 * - baseUrl: Custom base URL (optional)
 * - model: Model identifier
 * - temperature: Temperature parameter
 *
 * Returns:
 * - Streaming response if stream=true (default)
 * - Complete response if stream=false
 */
export async function POST(request: NextRequest) {
  try {
    // Parse request body
    const body = await request.json();
    const {
      prompt,
      messages,
      stream = true,
      apiKey: dynamicApiKey,
      baseUrl: dynamicBaseUrl,
      model: dynamicModel,
      temperature: dynamicTemperature
    } = body as {
      prompt?: string;
      messages?: Array<{ role: string, content: string }>;
      stream?: boolean;
      apiKey?: string;
      baseUrl?: string;
      model?: string;
      temperature?: number;
    };

    // Validate prompt or messages
    if (!prompt && (!messages || messages.length === 0)) {
      return new Response(
        JSON.stringify({
          success: false,
          error: {
            code: 'INVALID_REQUEST',
            message: 'Either prompt or messages array is required',
          },
          timestamp: new Date().toISOString(),
        }),
        { status: 400, headers: { 'Content-Type': 'application/json' } }
      );
    }

    // Determine config priority: Request Body > Environment Variables > Defaults
    const apiKey = dynamicApiKey || process.env.OPENAI_API_KEY;
    const baseUrl = dynamicBaseUrl || process.env.OPENAI_API_BASE_URL; // Optional env var for base URL
    const modelName = dynamicModel || process.env.LLM_MODEL || 'gpt-4o-mini';
    const temperature = dynamicTemperature ?? parseFloat(process.env.LLM_TEMPERATURE || '0.7');

    // Validate API Key presence
    if (!apiKey) {
      return new Response(
        JSON.stringify({
          success: false,
          error: {
            code: 'MISSING_API_KEY',
            message: 'API key is required in request body or server configuration',
          },
          timestamp: new Date().toISOString(),
        }),
        { status: 401, headers: { 'Content-Type': 'application/json' } }
      );
    }

    // Create provider based on whether it's OpenAI or a compatible provider
    // Use openai-compatible for non-OpenAI providers to ensure Chat Completions API is used
    const isOpenAI = !baseUrl || baseUrl.includes('api.openai.com');

    const provider = isOpenAI
      ? createOpenAI({ apiKey, baseURL: baseUrl })
      : createOpenAICompatible({
        name: 'custom-provider',
        baseURL: baseUrl,
        headers: {
          Authorization: `Bearer ${apiKey}`,
        },
      });

    // Prepare messages
    // If messages array is provided, use it. Otherwise convert legacy prompt to message
    const chatMessages = (messages || [{ role: 'user', content: prompt || '' }]) as any;

    // Return streaming or non-streaming response based on flag
    if (stream) {
      // Generate streaming response using AI SDK
      const result = streamText({
        model: provider(modelName),
        messages: chatMessages,
        temperature,
      });
      return result.toTextStreamResponse();
    }

    // For non-streaming, use generateText which returns the full text
    const { text } = await generateText({
      model: provider(modelName),
      messages: chatMessages,
      temperature,
    });

    return new Response(
      JSON.stringify({
        success: true,
        data: { text },
        timestamp: new Date().toISOString(),
      }),
      { status: 200, headers: { 'Content-Type': 'application/json' } }
    );

  } catch (error) {
    // Handle errors gracefully
    console.error('LLM API Error:', error);

    // Check for specific error types
    const errorMessage = error instanceof Error ? error.message : 'Unknown error';
    const isRateLimit = errorMessage.toLowerCase().includes('rate limit') || errorMessage.includes('429');
    const isTimeout = errorMessage.toLowerCase().includes('timeout');
    const isInvalidKey = errorMessage.toLowerCase().includes('invalid api key') || errorMessage.includes('401');
    const isNotFound = errorMessage.includes('404');

    let errorCode = 'INTERNAL_ERROR';
    if (isRateLimit) errorCode = 'RATE_LIMIT';
    if (isTimeout) errorCode = 'TIMEOUT';
    if (isInvalidKey) errorCode = 'INVALID_API_KEY';
    if (isNotFound) errorCode = 'MODEL_NOT_FOUND'; // Often 404 means model or endpoint not found

    return new Response(
      JSON.stringify({
        success: false,
        error: {
          code: errorCode,
          message: `Failed to generate response: ${errorMessage}`,
        },
        timestamp: new Date().toISOString(),
      }),
      { status: isInvalidKey ? 401 : 500, headers: { 'Content-Type': 'application/json' } }
    );
  }
}
