import { NextRequest, NextResponse } from "next/server";
import { JOB_APPLICATION_UPLOAD_CONFIG } from "@/lib/constants/storage.constants";
import { sendJobApplicationConfirmationEmail } from "@/lib/email";
import { convexMutation, convexQuery } from "@/lib/convex-client";
import { validateCSRFToken } from "@/lib/csrf";
import { corsResponse } from "@/lib/cors";

const MAX_FILE_SIZE = JOB_APPLICATION_UPLOAD_CONFIG.maxSizeBytes;
const ALLOWED_MIME_TYPES = new Set<string>([
  ...JOB_APPLICATION_UPLOAD_CONFIG.allowedMimeTypes,
]);

type Lang = "ar" | "en";

const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;

interface JobSummary {
  id: string;
  slug: string;
  title_translations: Record<string, string>;
  status: string;
  opening_at: string;
  closing_at: string | null;
}

const FALLBACK_JOB_TITLE: Record<Lang, string> = {
  en: "Open opportunity",
  ar: "فرصة وظيفية مفتوحة",
};

function slugify(value: string): string {
  return value
    .toLowerCase()
    .replace(/[^a-z0-9]+/gi, "-")
    .replace(/^-+|-+$/g, "")
    .trim();
}

function normaliseLang(value: string | null): Lang {
  return value === "ar" ? "ar" : "en";
}

function pickJobTitle(job: JobSummary, lang: Lang): string {
  const translations = job.title_translations || {};
  const translated = translations[lang];
  if (typeof translated === "string" && translated.trim().length > 0) {
    return translated.trim();
  }
  const english = translations.en;
  if (typeof english === "string" && english.trim().length > 0) {
    return english.trim();
  }
  return FALLBACK_JOB_TITLE[lang];
}

function isUuid(value: string): boolean {
  return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(
    value,
  );
}

export async function POST(request: NextRequest) {
  // CSRF validation (bypass in development for testing)
  if (process.env.NODE_ENV === "production") {
    if (!validateCSRFToken(request)) {
      return NextResponse.json(
        { error: "Invalid or missing CSRF token" },
        { status: 403 },
      );
    }
  }

  try {
    const formData = await request.formData();

    const jobId = (formData.get("jobId") as string | null)?.trim();
    const fullName = (formData.get("fullName") as string | null)?.trim();
    const email = (formData.get("email") as string | null)?.trim();
    const phone = (formData.get("phone") as string | null)?.trim();
    const coverLetter = (formData.get("coverLetter") as string | null)?.trim();
    const linkedIn = (formData.get("linkedIn") as string | null)?.trim();
    const portfolio = (formData.get("portfolio") as string | null)?.trim();
    const lang = normaliseLang(formData.get("lang") as string | null);
    const resume = formData.get("resume") as File | null;

    if (!jobId || !fullName || !email || !phone) {
      return NextResponse.json(
        { error: "Missing required fields" },
        { status: 400 },
      );
    }

    if (!EMAIL_REGEX.test(email)) {
      return NextResponse.json(
        { error: "Invalid email format" },
        { status: 400 },
      );
    }

    if (!resume) {
      return NextResponse.json(
        { error: "Resume is required" },
        { status: 400 },
      );
    }

    if (!ALLOWED_MIME_TYPES.has(resume.type)) {
      return NextResponse.json(
        { error: "Resume must be a PDF file" },
        { status: 400 },
      );
    }

    if (resume.size > MAX_FILE_SIZE) {
      return NextResponse.json(
        { error: "Resume file size must be 10MB or less" },
        { status: 400 },
      );
    }

    // Look up job via Convex
    const job = (await convexQuery("careers/queries:getJobByIdOrSlug", {
      idOrSlug: jobId,
      isUuid: isUuid(jobId),
    })) as JobSummary | null;

    if (!job) {
      console.error("Job not found in Convex", { jobId });
      return NextResponse.json(
        { error: "Selected job could not be found" },
        { status: 404 },
      );
    }

    const now = new Date();
    const openingAt = job.opening_at ? new Date(job.opening_at) : null;
    const closingAt = job.closing_at ? new Date(job.closing_at) : null;

    const isOpenStatus = job.status === "open";
    const withinWindow =
      (!openingAt || openingAt <= now) && (!closingAt || closingAt > now);

    if (!isOpenStatus || !withinWindow) {
      return NextResponse.json(
        { error: "This job is no longer accepting applications" },
        { status: 409 },
      );
    }

    // Upload CV to Convex storage
    const resumeBuffer = Buffer.from(await resume.arrayBuffer());
    const baseFilename = slugify(resume.name.replace(/\.pdf$/i, "")) || "cv";
    const applicantSegment = slugify(fullName) || "applicant";
    const cvFileName = `${now.getTime()}-${applicantSegment}-${baseFilename}.pdf`;

    // 1. Generate upload URL
    const uploadUrl = await convexMutation(
      "storage/mutations:generateUploadUrl",
      {},
    );
    if (!uploadUrl) {
      console.error("Failed to generate Convex upload URL for CV");
      return NextResponse.json(
        { error: "Failed to upload CV, please try again later" },
        { status: 500 },
      );
    }

    // 2. Upload file to Convex storage
    const uploadResult = await fetch(uploadUrl as string, {
      method: "POST",
      headers: { "Content-Type": resume.type },
      body: resumeBuffer,
    });

    if (!uploadResult.ok) {
      console.error("Failed to upload CV to Convex Storage", {
        status: uploadResult.status,
      });
      return NextResponse.json(
        { error: "Failed to upload CV, please try again later" },
        { status: 500 },
      );
    }

    const { storageId } = await uploadResult.json();

    // 3. Save file metadata
    await convexMutation("storage/mutations:saveFileMetadata", {
      storageId,
      fileName: cvFileName,
      fileType: resume.type,
      fileSize: resume.size,
      bucket: "job-cvs",
      entityType: "job_application",
    });

    const ipAddress =
      request.headers.get("x-forwarded-for") ||
      request.headers.get("x-real-ip") ||
      null;
    const userAgent = request.headers.get("user-agent") || null;

    // Insert job application record via Convex
    const applicationId = await convexMutation(
      "careers/mutations:createJobApplication",
      {
        job_id: job.id,
        applicant_name: fullName,
        applicant_email: email,
        applicant_phone: phone,
        applicant_linkedin: linkedIn || undefined,
        applicant_portfolio: portfolio || undefined,
        cover_note: coverLetter || undefined,
        cv_storage_id: storageId as string,
        cv_filename: resume.name,
        cv_bytes: resume.size,
        cv_mime_type: resume.type,
        submission_language: lang,
        metadata: {
          ipAddress: ipAddress || undefined,
          userAgent: userAgent || undefined,
        },
      },
    );

    if (!applicationId) {
      console.error("Failed to insert job application record");
      // Attempt to clean up uploaded file if insert fails
      try {
        await convexMutation("storage/mutations:deleteFile", { storageId });
      } catch (cleanupErr) {
        console.error("Failed to clean up CV after insert failure", cleanupErr);
      }
      return NextResponse.json(
        { error: "Failed to submit application, please try again later" },
        { status: 500 },
      );
    }

    const jobTitle = pickJobTitle(job, lang);

    console.info("Job application stored successfully", {
      applicationId,
      jobId: job.id,
      jobTitle,
      applicant: `${fullName} <${email}>`,
    });

    // Send confirmation email (non-blocking - don't fail application if email fails)
    sendJobApplicationConfirmationEmail(email, fullName, jobTitle, lang)
      .then((success) => {
        if (success) {
          console.info("Job application confirmation email sent", {
            applicationId,
            email: email.replace(/(.{2})(.*)(@.*)/, "$1***$3"),
          });
        } else {
          console.warn("Failed to send job application confirmation email", {
            applicationId,
            email: email.replace(/(.{2})(.*)(@.*)/, "$1***$3"),
          });
        }
      })
      .catch((error) => {
        console.error(
          "Error sending job application confirmation email:",
          error,
        );
      });

    return NextResponse.json(
      {
        success: true,
        message: "Application received successfully",
        applicationId,
      },
      { status: 200 },
    );
  } catch (error) {
    console.error("Job application error:", error);
    return NextResponse.json(
      { error: "Failed to process application" },
      { status: 500 },
    );
  }
}

export async function OPTIONS() {
  return corsResponse("POST, OPTIONS");
}
