/**
 * Input validation utility tests
 *
 * TRACES: UR-009, UR-025 | DR-015
 */

import { describe, it, expect } from "vitest";
import {
  validateItemId,
  validateImageType,
  validateMediaSourceId,
  validateNumericParam,
  validateQueryParamValue,
} from "./validation";

describe("validateItemId", () => {
  it("should accept valid item IDs", () => {
    expect(() => validateItemId("123abc")).not.toThrow();
    expect(() => validateItemId("abc-123_def")).not.toThrow();
    expect(() => validateItemId("12345")).not.toThrow();
  });

  it("should reject empty or non-string IDs", () => {
    expect(() => validateItemId("")).toThrow("must be a non-empty string");
    expect(() => validateItemId(null as any)).toThrow("must be a non-empty string");
    expect(() => validateItemId(undefined as any)).toThrow("must be a non-empty string");
  });

  it("should reject IDs exceeding max length", () => {
    expect(() => validateItemId("a".repeat(51))).toThrow("exceeds maximum length");
  });

  it("should reject IDs with invalid characters", () => {
    expect(() => validateItemId("abc/def")).toThrow("contains invalid characters");
    expect(() => validateItemId("abc..def")).toThrow("contains invalid characters");
    expect(() => validateItemId("abc def")).toThrow("contains invalid characters");
  });
});

describe("validateImageType", () => {
  it("should accept valid image types", () => {
    expect(() => validateImageType("Primary")).not.toThrow();
    expect(() => validateImageType("Backdrop")).not.toThrow();
    expect(() => validateImageType("Banner")).not.toThrow();
    expect(() => validateImageType("Logo")).not.toThrow();
  });

  it("should reject invalid image types", () => {
    expect(() => validateImageType("InvalidType")).toThrow("not a valid image type");
    expect(() => validateImageType("..")).toThrow("not a valid image type");
    expect(() => validateImageType("Primary/Avatar")).toThrow("not a valid image type");
  });

  it("should reject empty or non-string types", () => {
    expect(() => validateImageType("")).toThrow("must be a non-empty string");
  });
});

describe("validateMediaSourceId", () => {
  it("should accept valid media source IDs", () => {
    expect(() => validateMediaSourceId("source-123")).not.toThrow();
    expect(() => validateMediaSourceId("video_stream_1")).not.toThrow();
  });

  it("should reject IDs with invalid characters", () => {
    expect(() => validateMediaSourceId("source/path")).toThrow("contains invalid characters");
    expect(() => validateMediaSourceId("source..path")).toThrow("contains invalid characters");
  });

  it("should reject IDs exceeding max length", () => {
    expect(() => validateMediaSourceId("a".repeat(51))).toThrow("exceeds maximum length");
  });
});

describe("validateNumericParam", () => {
  it("should accept valid numbers", () => {
    expect(validateNumericParam(100)).toBe(100);
    expect(validateNumericParam(0)).toBe(0);
    expect(validateNumericParam(9999)).toBe(9999);
  });

  it("should reject non-integers", () => {
    expect(() => validateNumericParam(10.5)).toThrow("must be an integer");
    expect(() => validateNumericParam("100")).toThrow("must be an integer");
  });

  it("should respect min and max bounds", () => {
    expect(() => validateNumericParam(-1, 0, 100)).toThrow("must be between 0 and 100");
    expect(() => validateNumericParam(101, 0, 100)).toThrow("must be between 0 and 100");
  });

  it("should allow custom bounds", () => {
    expect(validateNumericParam(50, 10, 100)).toBe(50);
    expect(() => validateNumericParam(5, 10, 100)).toThrow("must be between 10 and 100");
  });
});

describe("validateQueryParamValue", () => {
  it("should accept valid query param values", () => {
    expect(() => validateQueryParamValue("abc123")).not.toThrow();
    expect(() => validateQueryParamValue("value-with-dash")).not.toThrow();
    expect(() => validateQueryParamValue("value_with_underscore")).not.toThrow();
  });

  it("should reject values with invalid characters", () => {
    expect(() => validateQueryParamValue("value with spaces")).toThrow("contains invalid characters");
    expect(() => validateQueryParamValue("value/path")).toThrow("contains invalid characters");
    expect(() => validateQueryParamValue("value?query")).toThrow("contains invalid characters");
  });

  it("should reject values exceeding max length", () => {
    expect(() => validateQueryParamValue("a".repeat(101))).toThrow("exceeds maximum length");
  });

  it("should respect custom max length", () => {
    expect(() => validateQueryParamValue("a".repeat(50), 40)).toThrow("exceeds maximum length");
  });
});
