/*
 * Copyright 2018-present Open Networking Foundation

 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at

 * http://www.apache.org/licenses/LICENSE-2.0

 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package afrouter

import (
	"errors"
	"fmt"
	"github.com/opencord/voltha-go/common/log"
	"google.golang.org/grpc"
	"google.golang.org/grpc/metadata"
)

type BindingRouter struct {
	name        string
	association associationType
	//routingField string
	grpcService string
	//protoDescriptor *pb.FileDescriptorSet
	//methodMap map[string]byte
	beCluster      *cluster
	bindings       map[string]*backend
	bindingType    string
	bindingField   string
	bindingMethod  string
	currentBackend **backend
}

func (br BindingRouter) IsStreaming(_ string) (bool, bool) {
	panic("not implemented")
}

func (br BindingRouter) BackendCluster(s string, metaKey string) (*cluster, error) {
	return br.beCluster, nil
	//return nil,errors.New("Not implemented yet")
}
func (br BindingRouter) Name() string {
	return br.name
}
func (br BindingRouter) Service() string {
	return br.grpcService
}
func (br BindingRouter) GetMetaKeyVal(serverStream grpc.ServerStream) (string, string, error) {
	var rtrnK = ""
	var rtrnV = ""

	// Get the metadata from the server stream
	md, ok := metadata.FromIncomingContext(serverStream.Context())
	if !ok {
		return rtrnK, rtrnV, errors.New("Could not get a server stream metadata")
	}

	// Determine if one of the method routing keys exists in the metadata
	if _, ok := md[br.bindingField]; ok == true {
		rtrnV = md[br.bindingField][0]
		rtrnK = br.bindingField
	}

	return rtrnK, rtrnV, nil
}
func (br BindingRouter) FindBackendCluster(becName string) *cluster {
	if becName == br.beCluster.name {
		return br.beCluster
	}
	return nil
}
func (br BindingRouter) ReplyHandler(v interface{}) error {
	return nil
}
func (br BindingRouter) Route(sel interface{}) *backend {
	var err error
	switch sl := sel.(type) {
	case *requestFrame:
		if b, ok := br.bindings[sl.metaVal]; ok == true { // binding exists, just return it
			return b
		} else { // establish a new binding or error.
			if sl.metaVal != "" {
				err = errors.New(fmt.Sprintf("Attempt to route on non-existent metadata value '%s' in key '%s'",
					sl.metaVal, sl.metaKey))
				log.Error(err)
				sl.err = err
				return nil
			}
			if sl.methodInfo.method != br.bindingMethod {
				err = errors.New(fmt.Sprintf("Binding must occur with method %s but attempted with method %s",
					br.bindingMethod, sl.methodInfo.method))
				log.Error(err)
				sl.err = err
				return nil
			}
			log.Debugf("MUST CREATE A NEW BINDING MAP ENTRY!!")
			if len(br.bindings) < len(br.beCluster.backends) {
				if *br.currentBackend, err = br.beCluster.nextBackend(*br.currentBackend, BackendSequenceRoundRobin); err == nil {
					// Use the name of the backend as the metaVal for this new binding
					br.bindings[(*br.currentBackend).name] = *br.currentBackend
					return *br.currentBackend
				} else {
					log.Error(err)
					sl.err = err
					return nil
				}
			} else {
				err = errors.New(fmt.Sprintf("Backends exhausted in attempt to bind for metakey '%s' with value '%s'",
					sl.metaKey, sl.metaVal))
				log.Error(err)
				sl.err = err
			}
		}
		return nil
	default:
		return nil
	}
}

func newBindingRouter(rconf *RouterConfig, config *RouteConfig) (Router, error) {
	var rtrn_err = false
	var err error = nil
	log.Debugf("Creating binding router %s", config.Name)
	// A name must exist
	if config.Name == "" {
		log.Error("A router 'name' must be specified")
		rtrn_err = true
	}

	if rconf.ProtoPackage == "" {
		log.Error("A 'package' must be specified")
		rtrn_err = true
	}

	if rconf.ProtoService == "" {
		log.Error("A 'service' must be specified")
		rtrn_err = true
	}

	//if config.RouteField == "" {
	//	log.Error("A 'routing_field' must be specified")
	//	rtrn_err = true
	//}

	// TODO: Using the specified service, the imported proto
	// descriptor file should be scanned for all methods provided
	// for this router to ensure that this field exists in
	// the message(s) passed to the method. This will avoid run
	// time failures that might not be detected for long periods
	// of time.

	// TODO The routes section is currently not being used
	// so the router will route all methods based on the
	// routing_field. This needs to be done.
	var bptr *backend
	bptr = nil
	br := BindingRouter{
		name:        config.Name,
		grpcService: rconf.ProtoService,
		bindings:    make(map[string]*backend),
		//methodMap:make(map[string]byte),
		currentBackend: &bptr,
		//serialNo:0,
	}

	// A binding association must exist
	br.association = config.Binding.Association
	if br.association == AssociationUndefined {
		log.Error("An binding association must be specified")
		rtrn_err = true
	}
	// A binding type must exist
	// TODO: This is parsed but ignored and a header based type is used.
	if config.Binding.Type != "header" {
		log.Error("The binding type must be set to header")
		rtrn_err = true
	} else {
		br.bindingType = config.Binding.Type
	}
	// A binding method must exist
	if config.Binding.Method == "" {
		log.Error("The binding method must be specified")
		rtrn_err = true
	} else {
		br.bindingMethod = config.Binding.Method
	}
	// A binding field must exxist
	if config.Binding.Field == "" {
		log.Error("The binding field must be specified")
		rtrn_err = true
	} else {
		br.bindingField = config.Binding.Field
	}

	// Create the backend cluster or link to an existing one
	ok := true
	if br.beCluster, ok = clusters[config.backendCluster.Name]; ok == false {
		if br.beCluster, err = newBackendCluster(config.backendCluster); err != nil {
			log.Errorf("Could not create a backend for router %s", config.Name)
			rtrn_err = true
		}
	}

	// HERE HERE HERE

	if rtrn_err {
		return br, errors.New(fmt.Sprintf("Failed to create a new router '%s'", br.name))
	}

	return br, nil
}
