/**
 * Unit Tests for Job Application Validation
 * Tests validation logic for job applications and CV uploads
 */

import { JOB_APPLICATION_UPLOAD_CONFIG } from "@/lib/constants/storage.constants";

describe("Job Application Validation", () => {
  describe("Email Validation", () => {
    const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;

    it("should validate correct email formats", () => {
      const validEmails = [
        "test@example.com",
        "user.name@company.co.uk",
        "first+last@domain.org",
        "email_123@test-domain.com",
      ];

      validEmails.forEach((email) => {
        expect(EMAIL_REGEX.test(email)).toBe(true);
      });
    });

    it("should reject invalid email formats", () => {
      const invalidEmails = [
        "notanemail",
        "@example.com",
        "user@",
        "user @example.com",
        "user@domain",
        "",
      ];

      invalidEmails.forEach((email) => {
        expect(EMAIL_REGEX.test(email)).toBe(false);
      });
    });
  });

  describe("Phone Validation", () => {
    it("should accept valid Saudi phone numbers", () => {
      const validPhones = ["+966501234567", "+966521234567", "+966541234567"];

      validPhones.forEach((phone) => {
        expect(phone.length).toBeGreaterThanOrEqual(10);
        expect(phone).toMatch(/^\+966/);
      });
    });

    it("should identify phone format patterns", () => {
      const phone = "+966501234567";
      expect(phone.startsWith("+966")).toBe(true);
      expect(phone.length).toBe(13);
    });
  });

  describe("CV File Validation", () => {
    const MAX_FILE_SIZE = JOB_APPLICATION_UPLOAD_CONFIG.maxSizeBytes;
    const ALLOWED_MIME_TYPES = new Set<string>([
      ...JOB_APPLICATION_UPLOAD_CONFIG.allowedMimeTypes,
    ]);

    it("should have correct file size limit", () => {
      expect(MAX_FILE_SIZE).toBe(10 * 1024 * 1024); // 10MB
    });

    it("should only allow PDF files", () => {
      expect(ALLOWED_MIME_TYPES.has("application/pdf")).toBe(true);
      expect(ALLOWED_MIME_TYPES.size).toBe(1);
    });

    it("should reject files exceeding size limit", () => {
      const fileSizeInBytes = 15 * 1024 * 1024; // 15MB
      expect(fileSizeInBytes > MAX_FILE_SIZE).toBe(true);
    });

    it("should accept files within size limit", () => {
      const fileSizeInBytes = 8 * 1024 * 1024; // 8MB
      expect(fileSizeInBytes <= MAX_FILE_SIZE).toBe(true);
    });

    it("should reject non-PDF mime types", () => {
      const invalidTypes = [
        "application/msword",
        "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
        "text/plain",
        "image/jpeg",
        "application/zip",
      ];

      invalidTypes.forEach((type) => {
        expect(ALLOWED_MIME_TYPES.has(type)).toBe(false);
      });
    });

    it("should validate PDF mime type", () => {
      const validType = "application/pdf";
      expect(ALLOWED_MIME_TYPES.has(validType)).toBe(true);
    });
  });

  describe("Required Fields Validation", () => {
    interface ApplicationData {
      jobId?: string;
      fullName?: string;
      email?: string;
      phone?: string;
      resume?: File | null;
    }

    const validateRequiredFields = (data: ApplicationData): boolean => {
      return Boolean(
        data.jobId?.trim() &&
        data.fullName?.trim() &&
        data.email?.trim() &&
        data.phone?.trim() &&
        data.resume,
      );
    };

    it("should validate complete application", () => {
      const validApplication: ApplicationData = {
        jobId: "job-123",
        fullName: "John Doe",
        email: "john@example.com",
        phone: "+966501234567",
        resume: new File(["content"], "cv.pdf", { type: "application/pdf" }),
      };

      expect(validateRequiredFields(validApplication)).toBe(true);
    });

    it("should reject application without jobId", () => {
      const invalidApplication: ApplicationData = {
        fullName: "John Doe",
        email: "john@example.com",
        phone: "+966501234567",
        resume: new File(["content"], "cv.pdf", { type: "application/pdf" }),
      };

      expect(validateRequiredFields(invalidApplication)).toBe(false);
    });

    it("should reject application without fullName", () => {
      const invalidApplication: ApplicationData = {
        jobId: "job-123",
        email: "john@example.com",
        phone: "+966501234567",
        resume: new File(["content"], "cv.pdf", { type: "application/pdf" }),
      };

      expect(validateRequiredFields(invalidApplication)).toBe(false);
    });

    it("should reject application without email", () => {
      const invalidApplication: ApplicationData = {
        jobId: "job-123",
        fullName: "John Doe",
        phone: "+966501234567",
        resume: new File(["content"], "cv.pdf", { type: "application/pdf" }),
      };

      expect(validateRequiredFields(invalidApplication)).toBe(false);
    });

    it("should reject application without phone", () => {
      const invalidApplication: ApplicationData = {
        jobId: "job-123",
        fullName: "John Doe",
        email: "john@example.com",
        resume: new File(["content"], "cv.pdf", { type: "application/pdf" }),
      };

      expect(validateRequiredFields(invalidApplication)).toBe(false);
    });

    it("should reject application without resume", () => {
      const invalidApplication: ApplicationData = {
        jobId: "job-123",
        fullName: "John Doe",
        email: "john@example.com",
        phone: "+966501234567",
        resume: null,
      };

      expect(validateRequiredFields(invalidApplication)).toBe(false);
    });

    it("should reject application with empty string fields", () => {
      const invalidApplication: ApplicationData = {
        jobId: "   ",
        fullName: "",
        email: "  ",
        phone: "+966501234567",
        resume: new File(["content"], "cv.pdf", { type: "application/pdf" }),
      };

      expect(validateRequiredFields(invalidApplication)).toBe(false);
    });
  });

  describe("Optional Fields Validation", () => {
    it("should handle optional LinkedIn URL", () => {
      const linkedIn = "https://linkedin.com/in/johndoe";
      expect(linkedIn).toBeTruthy();
      expect(linkedIn.includes("linkedin.com")).toBe(true);
    });

    it("should handle optional portfolio URL", () => {
      const portfolio = "https://johndoe.com";
      expect(portfolio).toBeTruthy();
      expect(portfolio.startsWith("http")).toBe(true);
    });

    it("should handle optional cover letter", () => {
      const coverLetter = "I am interested in this position...";
      expect(coverLetter).toBeTruthy();
      expect(coverLetter.length).toBeGreaterThan(0);
    });

    it("should handle missing optional fields", () => {
      const linkedIn = null;
      const portfolio = null;
      const coverLetter = null;

      expect(linkedIn || null).toBeNull();
      expect(portfolio || null).toBeNull();
      expect(coverLetter || null).toBeNull();
    });
  });

  describe("Language Normalization", () => {
    const normaliseLang = (value: string | null): "ar" | "en" => {
      return value === "ar" ? "ar" : "en";
    };

    it("should default to English", () => {
      expect(normaliseLang(null)).toBe("en");
      expect(normaliseLang("")).toBe("en");
      expect(normaliseLang("fr")).toBe("en");
    });

    it("should accept Arabic", () => {
      expect(normaliseLang("ar")).toBe("ar");
    });

    it("should accept English", () => {
      expect(normaliseLang("en")).toBe("en");
    });
  });

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

    it("should slugify filename correctly", () => {
      expect(slugify("John Doe CV")).toBe("john-doe-cv");
      expect(slugify("My Resume 2024.pdf")).toBe("my-resume-2024-pdf");
      expect(slugify("  Multiple   Spaces  ")).toBe("multiple-spaces");
    });

    it("should handle special characters", () => {
      expect(slugify("file@name#test")).toBe("file-name-test");
      expect(slugify("résumé_français")).toBe("r-sum-fran-ais");
    });

    it("should handle Arabic characters", () => {
      const arabicName = "سيرة ذاتية";
      const slugified = slugify(arabicName);
      // slugify strips non-ASCII chars, so Arabic text may produce empty string
      expect(typeof slugified).toBe("string");
    });
  });

  describe("UUID Validation", () => {
    const 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,
      );
    };

    it("should validate correct UUID format", () => {
      const validUuids = [
        "550e8400-e29b-41d4-a716-446655440000",
        "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
        "6ba7b811-9dad-11d1-80b4-00c04fd430c8",
      ];

      validUuids.forEach((uuid) => {
        expect(isUuid(uuid)).toBe(true);
      });
    });

    it("should reject invalid UUID formats", () => {
      const invalidUuids = [
        "not-a-uuid",
        "12345",
        "",
        "550e8400-e29b-41d4-a716",
        "job-slug-name",
      ];

      invalidUuids.forEach((uuid) => {
        expect(isUuid(uuid)).toBe(false);
      });
    });
  });
});
