/**
 * Voice Profile Parsing Endpoint
 * 
 * DEPRECATED: This endpoint is maintained for backward compatibility.
 * For new implementations, use /api/ai/voice-complete which provides
 * consolidated transcription + parsing + generation for better performance.
 * 
 * Performance: Use voice-complete for 30-50% faster processing
 */

import { NextRequest, NextResponse } from "next/server";
import { logger } from "@/lib/logger";
import OpenAI from "openai";
import { createClient } from "@/lib/supabase/server";
import { checkRateLimit, getClientIP, createRateLimitResponse } from "@/lib/rate-limit";
import { withErrorHandler, APIError, ErrorCodes } from "@/lib/api-errors";
import { sanitizeInput } from "@/lib/sanitize";
import { validateCSRFToken, isSameOrigin } from "@/lib/csrf";
import { TRADES } from "@/lib/constants";
import { 
  AI_RATE_LIMIT, 
  RATE_LIMIT_WINDOW_MS as AI_WINDOW_MS,
  MAX_LENGTH_TRANSCRIPT 
} from "@/lib/constants";

// Cast helper to use NextRequest methods while satisfying withErrorHandler signature
type Handler = (request: Request) => Promise<Response>;

if (!process.env.OPENAI_API_KEY) {
  throw new Error("OPENAI_API_KEY environment variable is not set");
}

const openai = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY,
});

// Rate limit: 10 requests per 15 minutes per user

const VALID_AVAILABILITY = ["full-time", "casual", "weekends", "flexible"];

async function handler(request: Request) {
  const nextRequest = request as NextRequest;
  // CSRF protection: validate same-origin and token
  if (!isSameOrigin(request)) {
    return NextResponse.json({ error: 'Cross-origin request not allowed' }, { status: 403 });
  }
  const csrfValid = await validateCSRFToken(request);
  if (!csrfValid) {
    return NextResponse.json({ error: 'Invalid or missing CSRF token' }, { status: 403 });
  }
  
  // Auth check
  const supabase = await createClient();
  const { data: { user } } = await supabase.auth.getUser();
  if (!user) {
    throw new APIError("Unauthorized", 401, ErrorCodes.UNAUTHORIZED);
  }

  // Rate limit
  const clientIP = getClientIP(request);
  const rateLimit = await checkRateLimit(`parse-voice:${clientIP}`, AI_RATE_LIMIT, AI_WINDOW_MS);
  if (!rateLimit.allowed) {
    const retryAfter = Math.ceil((rateLimit.resetTime - Date.now()) / 1000);
    return createRateLimitResponse(clientIP, retryAfter);
  }

  const body = await request.json();
  const { transcript } = body;

  if (!transcript || typeof transcript !== "string") {
    throw new APIError("Missing transcript", 400, ErrorCodes.INVALID_INPUT);
  }

  // Sanitize transcript to prevent prompt injection
  const sanitizedTranscript = sanitizeInput(transcript, { maxLength: MAX_LENGTH_TRANSCRIPT });

  try {
    const completion = await openai.chat.completions.create({
      model: "gpt-4o-mini",
      messages: [
        {
          role: "system",
          content: `You are a profile parser for an Australian construction hiring app. Extract structured data from a worker's spoken description.

Valid trades: ${TRADES.join(", ")}
Valid availability: ${VALID_AVAILABILITY.join(", ")}

Return ONLY valid JSON in this exact format:
{
  "trades": ["array of valid trades mentioned, or empty array"],
  "trade": "primary trade (first one mentioned) or null",
  "experience_years": number or null,
  "location": "suburb/area string or null",
  "availability": "one of the valid availability options or null",
  "additional_details": "any other details mentioned — specific skills, years per trade, preferences, work history, specialties. Capture everything not covered by the structured fields above. null if nothing extra."
}

Match trades loosely — e.g. "sparky" = "Electrician", "chippie" = "Carpenter", "bricky" = "Bricklayer", "steel fixer"/"steelfixer"/"reo" = "Steel Fixer", "formworker"/"formwork"/"shuttering"/"shutter hand" = "Formworker".
IMPORTANT: Extract ALL trades mentioned, not just one. If someone says "steel fixing and shuttering", return both "Steel Fixer" and "Formworker".
For experience, extract the number of years mentioned (use the highest if multiple are given for different trades).
For location, extract any suburb, city, or area name mentioned.
For availability, match to the closest option.
If a field is not mentioned, set it to null (or empty array for trades).`,
        },
        {
          role: "user",
          content: sanitizedTranscript,
        },
      ],
      temperature: 0.3,
      response_format: { type: "json_object" },
    });

    const content = completion.choices[0]?.message?.content;
    if (!content) {
      throw new APIError("No response from AI", 500, ErrorCodes.EXTERNAL_SERVICE_ERROR);
    }

    const parsed = JSON.parse(content);

    // Validate trades array
    if (Array.isArray(parsed.trades)) {
      parsed.trades = parsed.trades.filter((t: string) => (TRADES as readonly string[]).includes(t));
    } else {
      parsed.trades = [];
    }

    // Validate primary trade (use first from trades array if invalid)
    if (parsed.trade && !(TRADES as readonly string[]).includes(parsed.trade)) {
      parsed.trade = parsed.trades[0] || null;
    } else if (!parsed.trade && parsed.trades.length > 0) {
      parsed.trade = parsed.trades[0];
    }

    // Validate availability
    if (parsed.availability && !VALID_AVAILABILITY.includes(parsed.availability)) {
      parsed.availability = null;
    }

    // Validate experience_years
    if (parsed.experience_years !== null && (typeof parsed.experience_years !== "number" || parsed.experience_years < 0)) {
      parsed.experience_years = null;
    }

    return Response.json(parsed);
  } catch (error) {
    logger.error("OpenAI parsing error:", error);
    if (error instanceof APIError) {
      throw error;
    }
    throw new APIError(
      "Failed to parse voice input",
      500,
      ErrorCodes.EXTERNAL_SERVICE_ERROR
    );
  }
}

export const POST = withErrorHandler(handler);
