/**
 * Tests for URL Validator Utility
 */

import { describe, it, expect } from "vitest";
import { validateUrl } from "./url-validator";

describe("validateUrl", () => {
  describe("valid URLs", () => {
    it("should accept valid HTTP URL", () => {
      const result = validateUrl("http://orchestrator.example.com:3001");
      expect(result.valid).toBe(true);
      expect(result.error).toBeUndefined();
    });

    it("should accept valid HTTPS URL", () => {
      const result = validateUrl("https://orchestrator.example.com:3001");
      expect(result.valid).toBe(true);
      expect(result.error).toBeUndefined();
    });

    it("should accept URL without port", () => {
      const result = validateUrl("https://orchestrator.example.com");
      expect(result.valid).toBe(true);
      expect(result.error).toBeUndefined();
    });

    it("should accept URL with path", () => {
      const result = validateUrl("https://orchestrator.example.com:3001/api/v1");
      expect(result.valid).toBe(true);
      expect(result.error).toBeUndefined();
    });

    it("should accept localhost when allowLocalhost=true", () => {
      const result = validateUrl("http://localhost:3001", true);
      expect(result.valid).toBe(true);
      expect(result.error).toBeUndefined();
    });

    it("should accept 127.0.0.1 when allowLocalhost=true", () => {
      const result = validateUrl("http://127.0.0.1:3001", true);
      expect(result.valid).toBe(true);
      expect(result.error).toBeUndefined();
    });

    it("should accept public IP address", () => {
      const result = validateUrl("http://8.8.8.8:3001");
      expect(result.valid).toBe(true);
      expect(result.error).toBeUndefined();
    });
  });

  describe("invalid protocols", () => {
    it("should reject FTP protocol", () => {
      const result = validateUrl("ftp://orchestrator.example.com:3001");
      expect(result.valid).toBe(false);
      expect(result.error).toContain("Invalid orchestrator URL protocol");
    });

    it("should reject file protocol", () => {
      const result = validateUrl("file:///etc/passwd");
      expect(result.valid).toBe(false);
      expect(result.error).toContain("Invalid orchestrator URL protocol");
    });

    it("should reject javascript protocol", () => {
      const result = validateUrl("javascript:alert(1)");
      expect(result.valid).toBe(false);
      expect(result.error).toContain("Invalid orchestrator URL protocol");
    });

    it("should reject data protocol", () => {
      const result = validateUrl("data:text/html,<h1>test</h1>");
      expect(result.valid).toBe(false);
      expect(result.error).toContain("Invalid orchestrator URL protocol");
    });

    it("should reject gopher protocol", () => {
      const result = validateUrl("gopher://example.com");
      expect(result.valid).toBe(false);
      expect(result.error).toContain("Invalid orchestrator URL protocol");
    });
  });

  describe("malformed URLs", () => {
    it("should reject empty URL", () => {
      const result = validateUrl("");
      expect(result.valid).toBe(false);
      expect(result.error).toContain("Orchestrator URL is required");
    });

    it("should reject whitespace-only URL", () => {
      const result = validateUrl("   ");
      expect(result.valid).toBe(false);
      expect(result.error).toContain("Orchestrator URL is required");
    });

    it("should reject URL without protocol", () => {
      const result = validateUrl("orchestrator.example.com:3001");
      expect(result.valid).toBe(false);
      expect(result.error).toContain("Invalid orchestrator URL");
    });

    it("should reject invalid URL format", () => {
      const result = validateUrl("not a url at all");
      expect(result.valid).toBe(false);
      expect(result.error).toContain("Invalid orchestrator URL");
    });
  });

  describe("private IP addresses", () => {
    it("should reject localhost", () => {
      const result = validateUrl("http://localhost:3001");
      expect(result.valid).toBe(false);
      expect(result.error).toContain("private/internal addresses");
    });

    it("should reject 127.0.0.1", () => {
      const result = validateUrl("http://127.0.0.1:3001");
      expect(result.valid).toBe(false);
      expect(result.error).toContain("private/internal addresses");
    });

    it("should reject 127.x.x.x range", () => {
      const result = validateUrl("http://127.1.1.1:3001");
      expect(result.valid).toBe(false);
      expect(result.error).toContain("private/internal addresses");
    });

    it("should reject 0.0.0.0", () => {
      const result = validateUrl("http://0.0.0.0:3001");
      expect(result.valid).toBe(false);
      expect(result.error).toContain("private/internal addresses");
    });

    it("should reject 10.x.x.x range", () => {
      const result = validateUrl("http://10.0.0.1:3001");
      expect(result.valid).toBe(false);
      expect(result.error).toContain("private/internal addresses");
    });

    it("should reject 10.255.255.255", () => {
      const result = validateUrl("http://10.255.255.255:3001");
      expect(result.valid).toBe(false);
      expect(result.error).toContain("private/internal addresses");
    });

    it("should reject 192.168.x.x range", () => {
      const result = validateUrl("http://192.168.1.1:3001");
      expect(result.valid).toBe(false);
      expect(result.error).toContain("private/internal addresses");
    });

    it("should reject 192.168.0.1", () => {
      const result = validateUrl("http://192.168.0.1:3001");
      expect(result.valid).toBe(false);
      expect(result.error).toContain("private/internal addresses");
    });

    it("should reject 172.16.x.x range", () => {
      const result = validateUrl("http://172.16.0.1:3001");
      expect(result.valid).toBe(false);
      expect(result.error).toContain("private/internal addresses");
    });

    it("should reject 172.31.x.x (end of range)", () => {
      const result = validateUrl("http://172.31.255.255:3001");
      expect(result.valid).toBe(false);
      expect(result.error).toContain("private/internal addresses");
    });

    it("should accept 172.15.x.x (before private range)", () => {
      const result = validateUrl("http://172.15.0.1:3001");
      expect(result.valid).toBe(true);
      expect(result.error).toBeUndefined();
    });

    it("should accept 172.32.x.x (after private range)", () => {
      const result = validateUrl("http://172.32.0.1:3001");
      expect(result.valid).toBe(true);
      expect(result.error).toBeUndefined();
    });

    it("should reject 169.254.x.x (link-local)", () => {
      const result = validateUrl("http://169.254.1.1:3001");
      expect(result.valid).toBe(false);
      expect(result.error).toContain("private/internal addresses");
    });

    it("should reject ::1 (IPv6 localhost)", () => {
      const result = validateUrl("http://[::1]:3001");
      expect(result.valid).toBe(false);
      expect(result.error).toContain("private/internal addresses");
    });

    it("should reject :: (IPv6 any)", () => {
      const result = validateUrl("http://[::]:3001");
      expect(result.valid).toBe(false);
      expect(result.error).toContain("private/internal addresses");
    });

    it("should reject .localhost domain", () => {
      const result = validateUrl("http://app.localhost:3001");
      expect(result.valid).toBe(false);
      expect(result.error).toContain("private/internal addresses");
    });

    it("should reject .local domain", () => {
      const result = validateUrl("http://orchestrator.local:3001");
      expect(result.valid).toBe(false);
      expect(result.error).toContain("private/internal addresses");
    });
  });

  describe("allowLocalhost parameter", () => {
    it("should allow localhost when allowLocalhost=true", () => {
      const result = validateUrl("http://localhost:3001", true);
      expect(result.valid).toBe(true);
    });

    it("should allow 127.0.0.1 when allowLocalhost=true", () => {
      const result = validateUrl("http://127.0.0.1:3001", true);
      expect(result.valid).toBe(true);
    });

    it("should still reject 10.x.x.x even with allowLocalhost=true", () => {
      const result = validateUrl("http://10.0.0.1:3001", true);
      expect(result.valid).toBe(false);
      expect(result.error).toContain("private/internal addresses");
    });

    it("should still reject 192.168.x.x even with allowLocalhost=true", () => {
      const result = validateUrl("http://192.168.1.1:3001", true);
      expect(result.valid).toBe(false);
      expect(result.error).toContain("private/internal addresses");
    });
  });
});
