import { expect, test, describe } from "@jest/globals"
import { render, act } from "@testing-library/react"
import type { RenderResult } from "@testing-library/react"
import JSONSchemaViewer from "../../src/theme/JSONSchemaViewer/index"
import type { JSONSchema } from "../../src/theme/JSONSchemaViewer/types"
import CodeBlock from "../../__mocks__/@theme-original/CodeBlock"

describe("JSONSchemaViewer - constructor", () => {
  test("Overwrite default qualifierMessagesOrder value", async () => {
    const fakeSchema: JSONSchema = { type: "object", minProperties: 1 }
    let result: RenderResult | null = null

    await act(async () => {
      result = render(
        <JSONSchemaViewer
          schema={fakeSchema}
          viewerOptions={{ qualifierMessagesOrder: ["objectProperties"] }}
        />,
      )
    })

    expect(result!.asFragment()).toMatchSnapshot()
  })

  test("Overwrite default DescriptionComponent value", async () => {
    const fakeSchema2: JSONSchema = {
      type: "object",
      description: "# Hello, *world*!",
    }
    let result: RenderResult | null = null

    await act(async () => {
      result = render(
        <JSONSchemaViewer
          schema={fakeSchema2}
          viewerOptions={{
            DescriptionComponent: () => (
              <h1>
                Hello, <em>world</em>!
              </h1>
            ),
          }}
        />,
      )
    })

    expect(result!.asFragment()).toMatchSnapshot()
  })

  test("Overwrite default UnresolvedRefsComponent value", async () => {
    const fakeSchema: JSONSchema = {
      $schema: "https://json-schema.org/draft/2020-12/schema",
      $id: "https://example.com/tree",
      $dynamicAnchor: "node",
      type: "object",
      properties: {
        data: true,
        children: { type: "array", items: { $dynamicRef: "#node" } },
      },
    }
    let result: RenderResult | null = null

    await act(async () => {
      result = render(
        <JSONSchemaViewer
          schema={fakeSchema}
          viewerOptions={{
            UnresolvedRefsComponent: () => <>#node was not resolved</>,
          }}
        />,
      )
    })

    expect(result!.asFragment()).toMatchSnapshot()
  })

  test("Overwrite default ValueComponent value", async () => {
    const fakeSchema: JSONSchema = {
      $schema: "http://json-schema.org/draft-07/schema#",
      title: "CustomizationOptions",
      description: "JSON schema for customized options",
      type: "object",
      properties: {
        customField: {
          type: "string",
          description: "A customized or personalized field",
          enum: [
            "palette",
            "teddyBear",
            "tools",
            "laptop",
            "thread",
            "phone",
            "puzzle",
            "scissors",
            "hammer",
            "note",
          ],
          default: "palette",
          examples: ["tools", "note"],
        },
        customConstObject: { type: "object", const: { version: 5 } },
      },
      required: ["customField"],
      additionalProperties: false,
    }
    let result: RenderResult | null = null

    await act(async () => {
      result = render(
        <JSONSchemaViewer
          schema={fakeSchema}
          viewerOptions={{
            ValueComponent: ({ value, schema }) => {
              if (!["string", "number", "undefined"].includes(typeof value)) {
                return (
                  <CodeBlock language="json">{`${JSON.stringify(value, null, 2)}`}</CodeBlock>
                )
              }

              const component = <code>{`${value}`}</code>

              if (
                typeof schema !== "boolean" &&
                schema.default &&
                value === schema.default
              ) {
                return <strong>{component}</strong>
              }

              return component
            },
          }}
        />,
      )
    })

    expect(result!.asFragment()).toMatchSnapshot()
  })

  test("Overwrite default className value", async () => {
    const fakeSchema: JSONSchema = { type: "object", minProperties: 1 }
    let result: RenderResult | null = null

    await act(async () => {
      result = render(
        <JSONSchemaViewer schema={fakeSchema} className="jsv-custom" />,
      )
    })

    expect(result!.asFragment()).toMatchSnapshot()
  })

  test("Overwrite default defaultExpandDepth value", async () => {
    const fakeSchema: JSONSchema = {
      type: "object",
      properties: {
        level1_prop1: {
          type: "string",
        },
        level1_prop2: {
          type: "object",
          properties: {
            level2_prop1: {
              type: "integer",
            },
            level2_prop2: {
              type: "object",
              properties: {
                level3_prop1: {
                  type: "boolean",
                },
              },
            },
          },
        },
      },
    }
    let result: RenderResult | null = null

    await act(async () => {
      result = render(
        <JSONSchemaViewer
          schema={fakeSchema}
          viewerOptions={{ defaultExpandDepth: 2 }}
        />,
      )
    })

    expect(result!.asFragment()).toMatchSnapshot()
  })
})
