package resolvable

import (
	"reflect"

	"github.com/graph-gophers/graphql-go/ast"
	"github.com/graph-gophers/graphql-go/introspection"
)

// Meta defines the details of the metadata schema for introspection.
type Meta struct {
	FieldSchema   Field
	FieldType     Field
	FieldTypename Field
	FieldService  Field
	Schema        *Object
	Type          *Object
	Service       *Object
}

func newMeta(s *ast.Schema) *Meta {
	var err error
	b := newBuilder(s, false)

	metaSchema := s.Types["__Schema"].(*ast.ObjectTypeDefinition)
	so, err := b.populateObjectExec(&Object{}, metaSchema.Name, metaSchema.Fields, nil, nil, false, reflect.TypeFor[*introspection.Schema]())
	if err != nil {
		panic(err)
	}

	metaType := s.Types["__Type"].(*ast.ObjectTypeDefinition)
	t, err := b.populateObjectExec(&Object{}, metaType.Name, metaType.Fields, nil, nil, false, reflect.TypeFor[*introspection.Type]())
	if err != nil {
		panic(err)
	}

	if err := b.finish(); err != nil {
		panic(err)
	}

	fieldTypename := Field{
		FieldDefinition: ast.FieldDefinition{
			Name: "__typename",
			Type: &ast.NonNull{OfType: s.Types["String"]},
		},
		TraceLabel: "GraphQL field: __typename",
	}

	fieldSchema := Field{
		FieldDefinition: ast.FieldDefinition{
			Name: "__schema",
			Type: s.Types["__Schema"],
		},
		TraceLabel: "GraphQL field: __schema",
	}

	fieldType := Field{
		FieldDefinition: ast.FieldDefinition{
			Name: "__type",
			Type: s.Types["__Type"],
		},
		TraceLabel: "GraphQL field: __type",
	}

	return &Meta{
		FieldSchema:   fieldSchema,
		FieldTypename: fieldTypename,
		FieldType:     fieldType,
		Schema:        so,
		Type:          t,
	}
}
