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";
import { sendSms, SMS_TEMPLATES, isValidAuMobile } from "@/lib/sms";
import { HTTP_STATUS_INTERNAL_SERVER_ERROR } from "@/lib/constants";
import { recordMilestone } from "@/lib/success-tracking";

// Rate limit: 20 applies per 15 minutes
const RATE_LIMIT = 20;
const WINDOW_MS = 15 * 60 * 1000;

/**
 * POST /api/match/apply
 *
 * Worker applies for a job. Creates a match record and notifies the contractor.
 * Body: { job_id: string }
 */
const handler = async (request: NextRequest) => {
  try {
    // Rate limiting
    const clientIP = getClientIP(request);
    const rateLimit = await checkRateLimit(`apply:${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 } = await request.json();
    if (!jobId) {
      return NextResponse.json({ error: "job_id is required" }, { status: 400 });
    }

    const admin = getSupabaseAdmin();

    // Profile completeness gate — require minimum fields
    const [{ data: workerProfile }, { data: workerDetails }] = await Promise.all([
      admin.from("profiles").select("name, phone, type").eq("id", user.id).single(),
      admin.from("worker_profiles").select("trades, experience_years").eq("profile_id", user.id).single(),
    ]);

    if (workerProfile?.type !== "worker") {
      return NextResponse.json({ error: "Only workers can apply" }, { status: 403 });
    }

    const missingFields: string[] = [];
    if (!workerProfile?.name) missingFields.push("name");
    if (!workerProfile?.phone) missingFields.push("phone number");
    if (!workerDetails?.trades || workerDetails.trades.length === 0) missingFields.push("trade(s)");
    if (!workerDetails?.experience_years) missingFields.push("experience");

    if (missingFields.length > 0) {
      return NextResponse.json({
        error: `Complete your profile before applying. Missing: ${missingFields.join(", ")}`,
        missingFields,
        code: "INCOMPLETE_PROFILE",
      }, { status: 422 });
    }

    // Get job details including contractor's profile_id
    const { data: job, error: jobError } = await admin
      .from("jobs")
      .select("id, title, status, company_id, companies!inner(profile_id, name)")
      .eq("id", jobId)
      .single();

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

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

    // Prevent contractor from applying to their own job
    const companies = job.companies as unknown as { profile_id: string; name: string };
    if (companies.profile_id === user.id) {
      return NextResponse.json({ error: "Cannot apply to your own job" }, { status: 400 });
    }

    // Check if worker already applied
    const { data: existingMatch } = await admin
      .from("matches")
      .select("id, status")
      .eq("job_id", jobId)
      .eq("worker_id", user.id)
      .maybeSingle();

    if (existingMatch) {
      // If there's a suggested match, update it to applied
      if (existingMatch.status === "suggested") {
        await admin
          .from("matches")
          .update({
            status: "applied",
            worker_action: "accepted",
          })
          .eq("id", existingMatch.id);
      } else {
        return NextResponse.json({ error: "Already applied to this job" }, { status: 400 });
      }
    } else {
      // Create new match record
      const { error: insertError } = await admin
        .from("matches")
        .insert({
          job_id: jobId,
          worker_id: user.id,
          status: "applied",
          contractor_action: "pending",
          worker_action: "accepted",
        });

      if (insertError) {
        logger.error("Failed to create match:", insertError);
        return NextResponse.json({ error: "Failed to apply" }, { status: HTTP_STATUS_INTERNAL_SERVER_ERROR });
      }
    }

    // Get worker's name for the notification
    const { data: workerNameData } = await admin
      .from("profiles")
      .select("name")
      .eq("id", user.id)
      .single();

    const workerName = workerNameData?.name || "A worker";

    // Create notification for the contractor
    const { error: notifError } = await admin
      .from("notifications")
      .insert({
        profile_id: companies.profile_id,
        type: "match",
        title: `${workerName} applied for "${job.title}"`,
        body: `A worker has applied for your job listing. Tap to review and hire.`,
        data: { jobId, matchType: "applied" },
      });

    if (notifError) {
      // Log but don't fail the apply — the match was created successfully
      logger.error("Failed to create apply notification:", notifError);
    }

    // SMS to contractor (fire-and-forget)
    try {
      const { data: contractorProfile } = await admin
        .from("profiles")
        .select("phone")
        .eq("id", companies.profile_id)
        .single();

      if (contractorProfile?.phone && isValidAuMobile(contractorProfile.phone)) {
        sendSms(
          contractorProfile.phone,
          SMS_TEMPLATES.workerApplied(job.title, workerName)
        ).catch((err) => logger.error("Apply SMS failed:", err));
      }
    } catch (smsErr) {
      logger.error("SMS notification error on apply:", smsErr);
    }

    // Record first_application milestone (fire-and-forget)
    recordMilestone(user.id, "worker", "first_application", { job_id: jobId }).catch(() => {});

    return NextResponse.json({ success: true });
  } catch (error) {
    logger.error("Apply error:", error);
    return NextResponse.json(
      { error: "Failed to apply for job" },
      { status: HTTP_STATUS_INTERNAL_SERVER_ERROR }
    );
  }
};

export const POST = withCSRFProtection(handler);
