import { describe, expect, test } from "@jest/globals"

import { sanitize } from "./"

describe("sanitize", () => {
  test("should handle valid primitive attributes", () => {
    const input = {
      key1: "value1",
      key2: 10,
      key3: true,
    }
    const expected = {
      key1: "value1",
      key2: 10,
      key3: true,
    }
    expect(sanitize(input)).toEqual(expected)
  })

  test("should handle valid array attributes", () => {
    const input = {
      key1: ["value1", "value2"],
      key2: [1, 2, 3],
      key3: [true, false, true],
      key4: [null, undefined, "a", 1, true],
    }
    const expected = {
      "key1.0": "value1",
      "key1.1": "value2",
      "key2.0": 1,
      "key2.1": 2,
      "key2.2": 3,
      "key3.0": true,
      "key3.1": false,
      "key3.2": true,
      "key4.0": null,
      "key4.1": undefined,
      "key4.2": "a",
      "key4.3": 1,
      "key4.4": true,
    }
    expect(sanitize(input)).toEqual(expected)
  })

  test("should stringify non-valid attributes", () => {
    const input = {
      key1: new Date("2024-08-08T12:00:00Z"),
      key2: { nested: "object" },
    }
    const expected = {
      key1: '"2024-08-08T12:00:00.000Z"',
      "key2.nested": "object",
    }
    expect(sanitize(input)).toEqual(expected)
  })

  test("should handle nested valid attributes", () => {
    const input = {
      key1: "Example",
      key2: 10,
      nested: {
        nestedKey1: "Value",
        nestedKey2: {
          nestedKey2Key1: true,
        },
      },
    }
    const expected = {
      key1: "Example",
      key2: 10,
      "nested.nestedKey1": "Value",
      "nested.nestedKey2.nestedKey2Key1": true,
    }
    expect(sanitize(input)).toEqual(expected)
  })

  test("should handle a mix of valid and non-valid nested attributes", () => {
    const input = {
      key1: "Example",
      key2: 10,
      nested: {
        nestedKey1: "Value",
        nestedKey2: {
          nestedKey2Key1: true,
          nestedKey2Key2: new Date("2024-08-08T12:00:00Z"),
        },
        nestedKey3: {
          reallyNested: "hello",
        },
      },
      nonPrimitive: new Date("2024-08-08T13:00:00Z"),
    }
    const expected = {
      key1: "Example",
      key2: 10,
      "nested.nestedKey1": "Value",
      "nested.nestedKey2.nestedKey2Key1": true,
      "nested.nestedKey2.nestedKey2Key2": '"2024-08-08T12:00:00.000Z"',
      "nested.nestedKey3.reallyNested": "hello",
      nonPrimitive: '"2024-08-08T13:00:00.000Z"',
    }
    expect(sanitize(input)).toEqual(expected)
  })

  test("should throw an error when a function is passed", () => {
    const input = {
      key1: () => {},
    }
    expect(() => sanitize(input)).toThrowError("Cannot sanitize function")
  })

  test("should throw an error when input not an object", () => {
    // @ts-expect-error: array not allowed. We do this here to make sure the
    // function not only relies on TS but actively blocks arrays as input.
    expect(() => sanitize(null)).toThrowError()

    // @ts-expect-error: array not allowed. We do this here to make sure the
    // function not only relies on TS but actively blocks arrays as input.
    expect(() => sanitize(undefined)).toThrowError()

    // @ts-expect-error: array not allowed. We do this here to make sure the
    // function not only relies on TS but actively blocks arrays as input.
    expect(() => sanitize("")).toThrowError()

    // @ts-expect-error: array not allowed. We do this here to make sure the
    // function not only relies on TS but actively blocks arrays as input.
    expect(() => sanitize([1, 2, 3])).toThrowError()
  })

  test("should handle empty input", () => {
    const input = {}
    const expected = {}
    expect(sanitize(input)).toEqual(expected)
  })
})
