import { describe, expect, it } from "vitest";

import { Rectangle } from "@/lib/rects/rectangle";
import { Vector2D } from "@/lib/rects/vector2d";

describe("Rectangle Tests", () => {
  const v1 = new Vector2D(1, 2);
  const v2 = new Vector2D(4, 6);

  const r1 = new Rectangle(v1, v2);
  const r2 = new Rectangle(v2, v1);

  function check_rectangle(
    r: Rectangle,
    left: number,
    top: number,
    width: number,
    height: number,
  ): void {
    expect(r.left).toEqual(left);
    expect(r.top).toEqual(top);

    expect(r.width).toEqual(width);
    expect(r.height).toEqual(height);
    expect(r.area).toEqual(width * height);

    expect(r.middle.x).toEqual(left + 0.5 * width);
    expect(r.middle.y).toEqual(top + 0.5 * height);
  }

  it("should create a default rectangle", () => {
    expect.hasAssertions();
    check_rectangle(new Rectangle(), 0, 0, 0, 0);
  });

  it("should create a rectangle", () => {
    expect.hasAssertions();
    check_rectangle(r1, 1, 2, 3, 4);
  });

  it("should create the same rectangle backwards", () => {
    expect.hasAssertions();
    check_rectangle(r2, 1, 2, 3, 4);
  });

  it("should compare rectangles", () => {
    expect(r1.equals(r2)).toBe(true);
    expect(r1.equals(new Rectangle())).toBe(false);
  });

  it("should create the same rectangle transposed", () => {
    const v1t = new Vector2D(v1.x, v2.y);
    const v2t = new Vector2D(v2.x, v1.y);

    expect(r1.equals(new Rectangle(v1t, v2t))).toBe(true);
  });

  it("should contain itself", () => {
    expect(r1.contains(v1)).toBe(true);
    expect(r1.contains(v2)).toBe(true);

    expect(r1.contains(r1.origin)).toBe(true);
    expect(r1.contains(r1.corner)).toBe(true);
    expect(r1.contains(r1.middle)).toBe(true);
  });

  it("should not contain certain points", () => {
    expect(r1.contains(new Vector2D(0, 0))).toBe(false);
    expect(r1.contains(new Vector2D(100, 100))).toBe(false);
  });

  it("should update a rectangle", () => {
    expect.hasAssertions();
    const v = new Vector2D(1, 1);

    check_rectangle(r1.update(v1.plus(v), undefined), 2, 3, 2, 3);
    check_rectangle(r1.update(v1.minus(v), undefined), 0, 1, 4, 5);

    check_rectangle(r1.update(undefined, v2.plus(v)), 1, 2, 4, 5);
    check_rectangle(r1.update(undefined, v2.minus(v)), 1, 2, 2, 3);

    check_rectangle(r1.update(v1.plus(v), v2.plus(v)), 2, 3, 3, 4);
    check_rectangle(r1.update(v1.minus(v), v2.minus(v)), 0, 1, 3, 4);

    check_rectangle(r1.update(v1.minus(v), v2.plus(v)), 0, 1, 5, 6);
    check_rectangle(r1.update(v1.plus(v), v2.minus(v)), 2, 3, 1, 2);
  });

  it("should move a rectangle", () => {
    expect.hasAssertions();
    const v = new Vector2D(1, 1);

    check_rectangle(r1.move(v), 2, 3, 3, 4);
  });
});
