import { attest, contextualize } from "@ark/attest"
import { writeUnresolvableMessage } from "@ark/schema"
import { scope, type } from "arktype"

contextualize(() => {
	it("resolves from type", () => {
		const DisappointingGift = type({
			label: "string",
			"box?": "this"
		})

		type ExpectedDisappointingGift = {
			label: string
			box?: ExpectedDisappointingGift
		}
		attest<ExpectedDisappointingGift>(DisappointingGift.infer)

		attest(DisappointingGift({ label: "foo" })).snap({ label: "foo" })
		attest(DisappointingGift({ label: "foo", box: { label: "bar" } })).snap({
			label: "foo",
			box: { label: "bar" }
		})
		attest(
			DisappointingGift({
				label: "foo",
				box: { label: "bar", box: {} }
			}).toString()
		).snap("box.box.label must be a string (was missing)")
	})

	it("at nested path", () => {
		const T = type({ foo: { bar: "this" } })

		attest(T).type.toString.snap("Type<{ foo: { bar: cyclic } }, {}>")

		const validData = { foo: { bar: {} } } as typeof T.infer
		validData.foo.bar = validData

		attest(T(validData)).equals(validData)

		const invalidData = { foo: { bar: {} as any } }
		invalidData.foo.bar = invalidData.foo
		attest(T(invalidData).toString()).snap(
			"foo.bar.foo must be an object (was missing)"
		)
	})

	it("this preserved when referencing at path", () => {
		const Initial = type({
			initial: "this"
		})

		const Reference = type({
			reference: Initial
		})
		type Initial = {
			initial: Initial
		}
		type Expected = {
			reference: Initial
18:export type inferAstRoot<ast, $, args> =
19:	ast extends array ? inferExpression<ast, $, args> : never
21:export type inferAstIn<ast, $, args> = distill.In<inferAstRoot<ast, $, args>>
120:export type bindThis<def> = { this: Def<def> }
294:		if (!isScopeAlias && !ctx.args) ctx.args = { this: ctx.id }
