import { describe, expect, test } from "vitest";
import { isBlockedHost, validateProject, type ProjectFormValues } from "@/lib/validation/project";
import { validateSettings } from "@/lib/validation/settings";

const valid: ProjectFormValues = {
  projectCode: " 1118 ",
  projectName: " 2ndLine ",
  productionUrl: "https://api.example.com/health",
  monitoringEnabled: true,
  expectedHttpStatus: "",
  timeoutSeconds: "",
  description: "  ",
};

const errorsOf = (values: Partial<ProjectFormValues>) => {
  const result = validateProject({ ...valid, ...values });
  return result.ok ? {} : result.fieldErrors;
};

describe("project validation", () => {
  test("trims text, applies defaults (200 / 60s) and turns an empty description into null", () => {
    const result = validateProject(valid);
    expect(result).toEqual({
      ok: true,
      data: {
        projectCode: "1118",
        projectName: "2ndLine",
        productionUrl: "https://api.example.com/health",
        monitoringEnabled: true,
        expectedHttpStatus: 200,
        timeoutSeconds: 60,
        description: null,
      },
    });
  });

  test("required fields", () => {
    const errors = errorsOf({ projectCode: " ", projectName: "", productionUrl: "" });
    expect(Object.keys(errors).sort()).toEqual(["productionUrl", "projectCode", "projectName"]);
  });

  test("project code characters", () => {
    expect(errorsOf({ projectCode: "bad code!" }).projectCode).toBeDefined();
    expect(errorsOf({ projectCode: "APP_1.2-b" }).projectCode).toBeUndefined();
  });

  test.each(["ftp://example.com/x", "javascript:alert(1)", "example.com/health", "not a url"])("rejects URL %s", (url) => {
    expect(errorsOf({ productionUrl: url }).productionUrl).toBeDefined();
  });

  test("allows internal and local hosts but blocks cloud metadata addresses", () => {
    expect(errorsOf({ productionUrl: "http://localhost:8080/health" }).productionUrl).toBeUndefined();
    expect(errorsOf({ productionUrl: "http://10.0.0.5/health" }).productionUrl).toBeUndefined();
    expect(errorsOf({ productionUrl: "http://169.254.169.254/latest/meta-data" }).productionUrl).toBe("This host is not allowed");
    expect(isBlockedHost("metadata.google.internal")).toBe(true);
  });

  test.each([
    ["99", true],
    ["100", false],
    ["599", false],
    ["600", true],
    ["2xx", true],
    ["200.5", true],
    ["-200", true],
  ])("expected HTTP status %s invalid=%s", (value, invalid) => {
    expect(errorsOf({ expectedHttpStatus: value }).expectedHttpStatus !== undefined).toBe(invalid);
  });

  test.each([
    ["0", true],
    ["1", false],
    ["180", false],
    ["181", true],
    ["1.5", true],
  ])("timeout %s invalid=%s", (value, invalid) => {
    expect(errorsOf({ timeoutSeconds: value }).timeoutSeconds !== undefined).toBe(invalid);
  });
});

describe("settings validation", () => {
  const ok = { frequency: "EVERY_12_HOURS", checkTime: "09:00", timezone: "Asia/Kolkata", slowThresholdSeconds: "30" };

  test("accepts the defaults", () => {
    expect(validateSettings(ok)).toEqual({ ok: true, data: { ...ok, slowThresholdSeconds: 30 } });
  });

  test.each(["0", "171", "1.5", "30s", ""])("rejects slow-response threshold %j", (slowThresholdSeconds) => {
    const result = validateSettings({ ...ok, slowThresholdSeconds });
    expect(result.ok).toBe(false);
    if (!result.ok) expect(result.fieldErrors.slowThresholdSeconds).toBeDefined();
  });

  test.each(["24:00", "9:00", "09:60", "0900", ""])("rejects check time %j", (checkTime) => {
    expect(validateSettings({ ...ok, checkTime }).ok).toBe(false);
  });

  test("accepts Daily", () => {
    expect(validateSettings({ ...ok, frequency: "DAILY" }).ok).toBe(true);
  });

  test("rejects unknown timezones and frequencies that are not offered yet", () => {
    expect(validateSettings({ ...ok, timezone: "Mars/Olympus" }).ok).toBe(false);
    expect(validateSettings({ ...ok, frequency: "HOURLY" }).ok).toBe(false);
    expect(validateSettings({ ...ok, frequency: "EVERY_6_HOURS" }).ok).toBe(false);
    expect(validateSettings({ ...ok, frequency: "WEEKLY" }).ok).toBe(false);
  });
});
