import { describe, it, expect, beforeEach, afterEach } from "vitest";
import { ValidationError, validatePublishRequest } from "./validateRequest";

const ORIGINAL_ENV = { ...process.env };

function validBody(overrides: Record<string, unknown> = {}) {
  return {
    requestId: "event-test-1",
    submittedByEmail: "a@uwaterloo.ca",
    event: {
      name: "Test Event",
      short: "short",
      startDate: "August 05 2026 10:00",
      online: false,
      location: "DC 1351",
      descriptionMarkdown: "desc",
      year: 2026,
      term: "spring",
      slug: "test-event",
      poster: null,
      ...overrides,
    },
  };
}

describe("validatePublishRequest", () => {
  beforeEach(() => {
    process.env = { ...ORIGINAL_ENV };
  });
  afterEach(() => {
    process.env = { ...ORIGINAL_ENV };
  });

  it("accepts a well-formed request", () => {
    expect(() => validatePublishRequest(validBody())).not.toThrow();
  });

  it("rejects an unknown top-level field", () => {
    expect(() => validatePublishRequest({ ...validBody(), extra: "x" })).toThrow(ValidationError);
  });

  it("rejects a submittedByEmail that isn't @uwaterloo.ca", () => {
    const body = validBody();
    (body as any).submittedByEmail = "someone@gmail.com"; // long enough to pass the length check first
    expect(() => validatePublishRequest(body)).toThrow(/uwaterloo\.ca/);
  });

  it("rejects a slug that doesn't start with a letter or digit", () => {
    expect(() => validatePublishRequest(validBody({ slug: "-bad-slug" }))).toThrow(/slug/);
  });

  it("rejects a year that doesn't match startDate's year", () => {
    expect(() => validatePublishRequest(validBody({ year: 2027 }))).toThrow(/year/);
  });

  it("rejects an endDate that isn't after startDate", () => {
    expect(() =>
      validatePublishRequest(
        validBody({ endDate: "August 05 2026 09:00" }) // before the 10:00 startDate
      )
    ).toThrow(/endDate/);
  });

  describe("poster.sourceUrl origin allowlist (SSRF guard)", () => {
    it("rejects a poster URL pointing at an address outside the allowlist", () => {
      const body = validBody({
        poster: { sourceUrl: "https://169.254.169.254/latest/meta-data", filename: "a.png", contentType: "image/png" },
      });
      expect(() => validatePublishRequest(body)).toThrow(/not allowed/);
    });

    it("accepts a poster URL matching the configured PUBLIC_BASE_URL default", () => {
      const body = validBody({
        poster: { sourceUrl: "http://localhost:8001/uploads/abc.png", filename: "abc.png", contentType: "image/png" },
      });
      expect(() => validatePublishRequest(body)).not.toThrow();
    });

    it("rejects a poster filename containing a path separator", () => {
      const body = validBody({
        poster: { sourceUrl: "http://localhost:8001/uploads/abc.png", filename: "../abc.png", contentType: "image/png" },
      });
      expect(() => validatePublishRequest(body)).toThrow(/path separators/);
    });
  });
});
