package yangparser

import (
	"fmt"

	"code.fbi.h-da.de/danet/gosdn/controller/customerrs"
	"code.fbi.h-da.de/danet/gosdn/models/generated/openconfig"
	gpb "github.com/openconfig/gnmi/proto/gnmi"
	"github.com/openconfig/ygot/ygot"
	"github.com/openconfig/ygot/ytypes"
)

// Unmarshal injects OpenConfig specific model representation to the transport.
// Needed for type assertion.
func Unmarshal(bytes []byte, path *gpb.Path, goStruct ygot.GoStruct, opt ...ytypes.UnmarshalOpt) error {
	schema, err := openconfig.Schema()
	if err != nil {
		fmt.Println(err)
	}

	return unmarshal(schema, bytes, path, goStruct, opt...)
}

// unmarshal parses a gNMI response to a go struct.
func unmarshal(schema *ytypes.Schema, bytes []byte, path *gpb.Path, goStruct ygot.GoStruct, opt ...ytypes.UnmarshalOpt) error {
	defer func() {
		if r := recover(); r != nil {
			fmt.Println(r.(error))
		}
	}()

	// Load SBI definition
	root, err := ygot.DeepCopy(schema.Root)
	if err != nil {
		return err
	}
	validatedDeepCopy, ok := root.(ygot.ValidatedGoStruct)
	if !ok {
		return &customerrs.InvalidTypeAssertionError{
			Value: root,
			Type:  (*ygot.ValidatedGoStruct)(nil),
		}
	}

	// returns the node we want to fill with the data contained in 'bytes',
	// using the specified 'path'.
	createdNode, _, err := ytypes.GetOrCreateNode(schema.RootSchema(), validatedDeepCopy, path)
	if err != nil {
		return err
	}
	validatedCreatedNode, ok := createdNode.(ygot.ValidatedGoStruct)
	if !ok {
		return &customerrs.InvalidTypeAssertionError{
			Value: createdNode,
			Type:  (*ygot.ValidatedGoStruct)(nil),
		}
	}

	if err := openconfig.Unmarshal(bytes, validatedCreatedNode, opt...); err != nil {
		return err
	}

	opts := []ygot.MergeOpt{&ygot.MergeOverwriteExistingFields{}}
	return ygot.MergeStructInto(goStruct, validatedDeepCopy, opts...)
}
