import { describe, expect, it } from "vitest";
import { validate } from "class-validator";
import { plainToClass } from "class-transformer";
import { BaseFilterDto, BasePaginationDto, SortOrder } from "./base-filter.dto";

describe("BasePaginationDto", () => {
  it("should accept valid pagination parameters", async () => {
    const dto = plainToClass(BasePaginationDto, {
      page: 1,
      limit: 20,
    });

    const errors = await validate(dto);
    expect(errors.length).toBe(0);
    expect(dto.page).toBe(1);
    expect(dto.limit).toBe(20);
  });

  it("should use default values when not provided", async () => {
    const dto = plainToClass(BasePaginationDto, {});

    const errors = await validate(dto);
    expect(errors.length).toBe(0);
  });

  it("should reject page less than 1", async () => {
    const dto = plainToClass(BasePaginationDto, {
      page: 0,
    });

    const errors = await validate(dto);
    expect(errors.length).toBeGreaterThan(0);
    expect(errors[0].property).toBe("page");
  });

  it("should reject limit less than 1", async () => {
    const dto = plainToClass(BasePaginationDto, {
      limit: 0,
    });

    const errors = await validate(dto);
    expect(errors.length).toBeGreaterThan(0);
    expect(errors[0].property).toBe("limit");
  });

  it("should reject limit greater than 100", async () => {
    const dto = plainToClass(BasePaginationDto, {
      limit: 101,
    });

    const errors = await validate(dto);
    expect(errors.length).toBeGreaterThan(0);
    expect(errors[0].property).toBe("limit");
  });

  it("should transform string numbers to integers", async () => {
    const dto = plainToClass(BasePaginationDto, {
      page: "2" as any,
      limit: "30" as any,
    });

    const errors = await validate(dto);
    expect(errors.length).toBe(0);
    expect(dto.page).toBe(2);
    expect(dto.limit).toBe(30);
  });
});

describe("BaseFilterDto", () => {
  it("should accept valid search parameter", async () => {
    const dto = plainToClass(BaseFilterDto, {
      search: "test query",
    });

    const errors = await validate(dto);
    expect(errors.length).toBe(0);
    expect(dto.search).toBe("test query");
  });

  it("should accept valid sortBy parameter", async () => {
    const dto = plainToClass(BaseFilterDto, {
      sortBy: "createdAt",
    });

    const errors = await validate(dto);
    expect(errors.length).toBe(0);
    expect(dto.sortBy).toBe("createdAt");
  });

  it("should accept valid sortOrder parameter", async () => {
    const dto = plainToClass(BaseFilterDto, {
      sortOrder: SortOrder.DESC,
    });

    const errors = await validate(dto);
    expect(errors.length).toBe(0);
    expect(dto.sortOrder).toBe(SortOrder.DESC);
  });

  it("should reject invalid sortOrder", async () => {
    const dto = plainToClass(BaseFilterDto, {
      sortOrder: "invalid" as any,
    });

    const errors = await validate(dto);
    expect(errors.length).toBeGreaterThan(0);
    expect(errors.some((e) => e.property === "sortOrder")).toBe(true);
  });

  it("should accept comma-separated sortBy fields", async () => {
    const dto = plainToClass(BaseFilterDto, {
      sortBy: "priority,createdAt",
    });

    const errors = await validate(dto);
    expect(errors.length).toBe(0);
    expect(dto.sortBy).toBe("priority,createdAt");
  });

  it("should accept date range filters", async () => {
    const dto = plainToClass(BaseFilterDto, {
      dateFrom: "2024-01-01T00:00:00Z",
      dateTo: "2024-12-31T23:59:59Z",
    });

    const errors = await validate(dto);
    expect(errors.length).toBe(0);
  });

  it("should reject invalid date format for dateFrom", async () => {
    const dto = plainToClass(BaseFilterDto, {
      dateFrom: "not-a-date",
    });

    const errors = await validate(dto);
    expect(errors.length).toBeGreaterThan(0);
    expect(errors.some((e) => e.property === "dateFrom")).toBe(true);
  });

  it("should reject invalid date format for dateTo", async () => {
    const dto = plainToClass(BaseFilterDto, {
      dateTo: "not-a-date",
    });

    const errors = await validate(dto);
    expect(errors.length).toBeGreaterThan(0);
    expect(errors.some((e) => e.property === "dateTo")).toBe(true);
  });

  it("should trim whitespace from search query", async () => {
    const dto = plainToClass(BaseFilterDto, {
      search: "  test query  ",
    });

    const errors = await validate(dto);
    expect(errors.length).toBe(0);
    expect(dto.search).toBe("test query");
  });

  it("should reject search queries longer than 500 characters", async () => {
    const longString = "a".repeat(501);
    const dto = plainToClass(BaseFilterDto, {
      search: longString,
    });

    const errors = await validate(dto);
    expect(errors.length).toBeGreaterThan(0);
    expect(errors.some((e) => e.property === "search")).toBe(true);
  });
});
