/*
 * Copyright (c) Microsoft Corporation.
 * Licensed under the MIT license.
 */

package astmodel

import (
	"testing"

	. "github.com/onsi/gomega"
)

func TestAllOfOneTypeReturnsThatType(t *testing.T) {
	t.Parallel()
	g := NewGomegaWithT(t)

	oneType := StringType
	result := BuildAllOfType(oneType)

	g.Expect(result).To(BeIdenticalTo(oneType))
}

func TestAllOfIdenticalTypesReturnsThatType(t *testing.T) {
	t.Parallel()
	g := NewGomegaWithT(t)

	oneType := StringType
	result := BuildAllOfType(oneType, oneType)

	g.Expect(result).To(BeIdenticalTo(oneType))
}

func TestAllOfFlattensNestedAllOfs(t *testing.T) {
	t.Parallel()
	g := NewGomegaWithT(t)

	result := BuildAllOfType(BoolType, BuildAllOfType(StringType, IntType))

	expected := BuildAllOfType(BoolType, StringType, IntType)

	g.Expect(result).To(Equal(expected))
}

func TestAllOfOneOfBecomesOneOfAllOf(t *testing.T) {
	t.Parallel()
	g := NewGomegaWithT(t)

	oneOf := NewOneOfType("TestOneOf", StringType, FloatType)
	result := BuildAllOfType(BoolType, IntType, oneOf)

	expected := NewOneOfType(
		"TestOneOf",
		BuildAllOfType(BoolType, IntType, StringType),
		BuildAllOfType(BoolType, IntType, FloatType),
	)

	g.Expect(result).To(Equal(expected))
}

func TestAllOfEqualityDoesNotCareAboutOrder(t *testing.T) {
	t.Parallel()
	g := NewGomegaWithT(t)

	x := BuildAllOfType(StringType, BoolType)
	y := BuildAllOfType(BoolType, StringType)

	g.Expect(TypeEquals(x, y)).To(BeTrue())
	g.Expect(TypeEquals(y, x)).To(BeTrue())
}

func TestAllOfMustHaveAllTypesToBeEqual(t *testing.T) {
	t.Parallel()
	g := NewGomegaWithT(t)

	x := BuildAllOfType(StringType, BoolType, FloatType)
	y := BuildAllOfType(BoolType, StringType)

	g.Expect(TypeEquals(x, y)).To(BeFalse())
	g.Expect(TypeEquals(y, x)).To(BeFalse())
}

func TestAllOfsWithDifferentTypesAreNotEqual(t *testing.T) {
	t.Parallel()
	g := NewGomegaWithT(t)

	x := BuildAllOfType(StringType, FloatType)
	y := BuildAllOfType(BoolType, StringType)

	g.Expect(TypeEquals(x, y)).To(BeFalse())
	g.Expect(TypeEquals(y, x)).To(BeFalse())
}

var expectedAllOfPanic = "AllOfType should have been replaced by generation time by 'convertAllOfAndOneOf' phase"

func TestAllOfAsTypePanics(t *testing.T) {
	t.Parallel()
	g := NewGomegaWithT(t)

	x := AllOfType{}
	g.Expect(func() {
		_, err := x.AsTypeExpr(&CodeGenerationContext{})
		g.Expect(err).To(BeNil()) // Unreachable, but keeps lint happy
	}).To(PanicWith(MatchError(expectedAllOfPanic)))
}

func TestAllOfAsDeclarationsPanics(t *testing.T) {
	t.Parallel()
	g := NewGomegaWithT(t)

	x := AllOfType{}
	g.Expect(func() {
		//nolint:errcheck // error will never be returned due to panic
		x.AsDeclarations(&CodeGenerationContext{}, DeclarationContext{})
	}).To(PanicWith(MatchError(expectedAllOfPanic)))
}

func TestAllOfRequiredImportsPanics(t *testing.T) {
	t.Parallel()
	g := NewGomegaWithT(t)

	x := AllOfType{}
	g.Expect(func() {
		x.RequiredPackageReferences()
	}).To(PanicWith(MatchError(expectedAllOfPanic)))
}
