/*
 * 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.
 */
// gRPC affinity router with active/active backends

package afrouter

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

const NoMeta = "nometa"

type MethodRouter struct {
	name string
	service string
	mthdRt map[string]map[string]Router // map of [metadata][method]
}

func newMethodRouter(config *RouterConfig) (Router, error) {
	mr := MethodRouter{name:config.Name,service:config.ProtoService,mthdRt:make(map[string]map[string]Router)}
	mr.mthdRt[NoMeta] = make(map[string]Router) // For routes not needing metadata (all expcept binding at this time)
	if len(config.Routes) == 0 {
		return nil, errors.New(fmt.Sprintf("Router %s must have at least one route", config.Name))
	}
	for _,rtv := range config.Routes {
		var idx1 string
		r,err := newSubRouter(config, &rtv)
		if err != nil {
			return nil, err
		}
		if rtv.Type == "binding" {
			idx1 = rtv.Binding.Field
			if _,ok := mr.mthdRt[idx1]; ok == false { // /First attempt on this key
				mr.mthdRt[idx1] = make(map[string]Router)
			}
		} else {
			idx1 = NoMeta
		}
		switch len(rtv.Methods) {
		case 0:
			return nil, errors.New(fmt.Sprintf("Route for router %s must have at least one method", config.Name))
		case 1:
			if rtv.Methods[0] == "*" {
				return r, nil
			} else {
				log.Debugf("Setting router '%s' for single method '%s'",r.Name(),rtv.Methods[0])
				if _,ok := mr.mthdRt[""][rtv.Methods[0]]; ok == false {
					mr.mthdRt[idx1][rtv.Methods[0]] = r
				} else {
					err := errors.New(fmt.Sprintf("Attempt to define method %s for 2 routes: %s & %s", rtv.Methods[0],
						r.Name(), mr.mthdRt[idx1][rtv.Methods[0]].Name()))
					log.Debug(err)
					return mr, err
				}
			}
		default:
			for _,m := range rtv.Methods {
				log.Debugf("Setting router '%s' for method '%s'",r.Name(),m)
				if _,ok := mr.mthdRt[idx1][m]; ok == false {
					mr.mthdRt[idx1][m] = r
				} else {
					err := errors.New(fmt.Sprintf("Attempt to define method %s for 2 routes: %s & %s", rtv.Methods[0],
						r.Name(), mr.mthdRt[idx1][m].Name()))
					log.Debug(err)
					return mr, err
				}
			}
		}
	}

	return mr, nil
}

func (mr MethodRouter) Name() string {
	return mr.name
}

func (mr MethodRouter) Service() string {
	return mr.service
}

func (mr MethodRouter) GetMetaKeyVal(serverStream grpc.ServerStream) (string,string,error) {
	var rtrnK string = NoMeta
	var rtrnV string = ""

	// 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
	for k,_ := range mr.mthdRt {
		if  _,ok := md[k]; ok == true {
			rtrnV = md[k][0]
			rtrnK = k
			break
		}
	}
	return rtrnK,rtrnV,nil

}

func (mr MethodRouter) ReplyHandler(sel interface{}) error {
	switch sl := sel.(type) {
		case *sbFrame:
			if r,ok := mr.mthdRt[NoMeta][sl.method]; ok == true {
				return r.ReplyHandler(sel)
			}
			// TODO: this case should also be an error
		default: //TODO: This should really be a big error
			// A reply handler should only be called on the sbFrame
			return nil
	}
	return nil
}

func (mr MethodRouter) Route(sel interface{}) *backend {
	switch sl := sel.(type) {
		case *nbFrame:
			if r,ok := mr.mthdRt[sl.metaKey][sl.mthdSlice[REQ_METHOD]]; ok == true {
				return r.Route(sel)
			}
			log.Errorf("Attept to route on non-existent method '%s'", sl.mthdSlice[REQ_METHOD])
			return nil
		default:
			return nil
	}
	return nil
}

func (mr MethodRouter) BackendCluster(mthd string, metaKey string) (*backendCluster,error) {
	if r,ok := mr.mthdRt[metaKey][mthd]; ok == true {
		return r.BackendCluster(mthd, metaKey)
	}
	err := errors.New(fmt.Sprintf("No backend cluster exists for method '%s' using meta key '%s'", mthd,metaKey))
	log.Error(err)
	return nil, err
}

func (mr MethodRouter) FindBackendCluster(beName string) *backendCluster {
	for _,meta := range mr.mthdRt {
		for _,r := range meta {
			if rtrn := r.FindBackendCluster(beName); rtrn != nil   {
				return rtrn
			}
		}
	}
	return nil
}
