import { NextRequest, NextResponse } from "next/server";
import { logger } from "@/lib/logger";
import { createClient, getSupabaseAdmin } from "@/lib/supabase/server";
import { checkRateLimit, getClientIP, createRateLimitResponse } from "@/lib/rate-limit";
import { withCSRFProtection } from "@/lib/csrf";

// Rate limit: 10 requests per 15 minutes
const RATE_LIMIT = 10;
const WINDOW_MS = 15 * 60 * 1000;

/**
 * POST /api/match/find-matches
 *
 * Finds and creates suggested matches for a job using DB-side scoring.
 * Body: { job_id: string, limit?: number, min_score?: number }
 *
 * Scoring weights (calculated in database):
 * - Trade match: 40%
 * - Availability: 20%
 * - Experience: 15%
 * - Certifications: 15%
 * - Location proximity: 10%
 * - Ratings: 10%
 *
 * NOTE: This uses the find_matching_workers() RPC function which scales
 * efficiently to 10k+ workers by performing all scoring calculations
 * database-side with proper indexes.
 */
const handler = async (request: NextRequest) => {
  try {
    // Rate limiting
    const clientIP = getClientIP(request);
    const rateLimit = await checkRateLimit(`match:${clientIP}`, RATE_LIMIT, WINDOW_MS);
    if (!rateLimit.allowed) {
      const retryAfter = Math.ceil((rateLimit.resetTime - Date.now()) / 1000);
      return createRateLimitResponse(clientIP, retryAfter);
    }

    // Auth check
    const supabase = await createClient();
    const { data: { user }, error: authError } = await supabase.auth.getUser();
    if (authError || !user) {
      return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
    }

    const { job_id: jobId, limit = 20, min_score: minScore } = await request.json();
    if (!jobId) {
      return NextResponse.json({ error: "job_id is required" }, { status: 400 });
    }

    // Validate limit (prevent abuse)
    const validLimit = Math.min(Math.max(parseInt(limit as string) || 20, 1), 50);
    const validMinScore = Math.min(Math.max(parseInt(minScore as string) || 20, 0), 100);

    // Use admin client to bypass RLS for matching operations
    const admin = getSupabaseAdmin();

    // Verify job exists and user owns it
    const { data: job, error: jobError } = await admin
      .from("jobs")
      .select("id, status, companies!inner(profile_id)")
      .eq("id", jobId)
      .single();

    if (jobError || !job) {
      return NextResponse.json({ error: "Job not found" }, { status: 404 });
    }

    // Verify the requesting user owns this job's company
    const companies = job.companies as unknown as { profile_id: string } | null;
    if (!companies || companies.profile_id !== user.id) {
      return NextResponse.json({ error: "Not authorized for this job" }, { status: 403 });
    }

    if (job.status !== "active") {
      return NextResponse.json({ error: "Job is not active" }, { status: 400 });
    }

    // Call the DB-side scoring RPC function
    // This is the key optimization - all scoring happens in the database
    const { data: scoredWorkers, error: rpcError } = await admin.rpc(
      "find_matching_workers",
      {
        p_job_id: jobId,
        p_limit: validLimit,
        p_min_score: validMinScore,
      }
    );

    if (rpcError) {
      logger.error("RPC error finding matches:", rpcError);
      return NextResponse.json(
        { error: "Failed to find matches" },
        { status: 500 }
      );
    }

    if (!scoredWorkers || scoredWorkers.length === 0) {
      return NextResponse.json({
        matches: [],
        message: "No matching workers found",
        matches_created: 0,
      });
    }

    // Prepare match rows for insertion
    const matchRows = scoredWorkers.map((match: {
      worker_id: string;
      score: number;
      summary: string;
    }) => ({
      job_id: jobId,
      worker_id: match.worker_id,
      status: "suggested" as const,
      match_score: match.score,
      ai_summary: match.summary,
      contractor_action: "pending" as const,
      worker_action: "pending" as const,
    }));

    // Insert matches into the database
    const { error: insertError } = await admin
      .from("matches")
      .upsert(matchRows, { onConflict: "job_id,worker_id", ignoreDuplicates: true });

    if (insertError) {
      logger.error("Error inserting matches:", insertError);
      return NextResponse.json({ error: "Failed to save matches" }, { status: 500 });
    }

    // Notify the contractor about new matches
    if (scoredWorkers.length > 0) {
      const jobTitle = (await admin
        .from("jobs")
        .select("title")
        .eq("id", jobId)
        .single()).data?.title || "your job";

      const { error: notifError } = await admin
        .from("notifications")
        .insert({
          profile_id: user.id,
          type: "match",
          title: `${scoredWorkers.length} worker${scoredWorkers.length > 1 ? "s" : ""} matched for "${jobTitle}"`,
          body: "Tap to review matches and hire the best fit.",
          data: { jobId, matchType: "suggested", count: scoredWorkers.length },
        });

      if (notifError) {
        logger.error("Failed to create match notification:", notifError);
      }
    }

    return NextResponse.json({
      matches: scoredWorkers.map((m: {
        worker_id: string;
        score: number;
        summary: string;
        reasons: string[];
        profile: Record<string, unknown>;
      }) => ({
        worker_id: m.worker_id,
        score: m.score,
        summary: m.summary,
        reasons: m.reasons,
        profile: m.profile,
      })),
      matches_created: scoredWorkers.length,
    });
  } catch (error) {
    logger.error("Match finding error:", error);
    return NextResponse.json(
      { error: "Failed to find matches" },
      { status: 500 }
    );
  }
}

// Apply CSRF protection to the handler
export const POST = withCSRFProtection(handler);
