// Copyright (c) Shenyang Leading Edge Intelligent Technology Co., Ltd. All rights reserved.

package rpc

import (
	"LAPP_LF_MOM_BACKEND/container"
	"fmt"
	"github.com/kataras/iris/v12/core/router"
	"reflect"
	"strings"
)

type ServiceRouteManager struct {
	componentContainer container.ComponentContainer
	serviceType        reflect.Type
	alias              string
	routeFactories     map[string]func(router.Party, string, reflect.Type, func([]reflect.Value) []reflect.Value) error
}

func NewServiceRouteManager(componentContainer container.ComponentContainer, serviceType reflect.Type) *ServiceRouteManager {
	return &ServiceRouteManager{componentContainer, serviceType, "", make(map[string]func(router.Party, string, reflect.Type, func([]reflect.Value) []reflect.Value) error, 10)}
}

func (manager *ServiceRouteManager) SetAlias(value string) *ServiceRouteManager {
	manager.alias = value
	return manager
}

func (manager *ServiceRouteManager) RegisterRoute(methodName string, routeFactory func(router.Party, string, reflect.Type, func([]reflect.Value) []reflect.Value) error) *ServiceRouteManager {
	manager.routeFactories[methodName] = routeFactory
	return manager
}

func (manager *ServiceRouteManager) BindRoutes(pathMapping map[string][]string, party router.Party) {
	packageList := strings.Split(manager.serviceType.PkgPath(), container.PathSeparator)
	servicePackagePath := ""
	for index, packageName := range packageList {
		if strings.ToLower(packageName) == container.ServicesPackageName {
			servicePackagePath = strings.Join(packageList[index+1:], container.PathSeparator)
			break
		}
	}
	serviceTypeName := manager.serviceType.Name()
	serviceName := ""
	if manager.alias != "" {
		serviceName = manager.alias
	} else {
		serviceName = serviceTypeName[:len(serviceTypeName)-len(container.ServiceNameSuffix)]
	}
	servicePath := strings.ToLower(fmt.Sprintf("/%s/%s", servicePackagePath, serviceName))
	group, ok := pathMapping[servicePath]
	if !ok {
		group = make([]string, 0, 10)
	}
	pathMapping[servicePath] = append(group, serviceName)

	for i := 0; i < manager.serviceType.NumMethod(); i++ {
		method := manager.serviceType.Method(i)
		methodFullName := fmt.Sprintf("%s/%s.%s", servicePackagePath, serviceTypeName, method.Name)
		caller := manager.componentContainer.GetServiceCaller(methodFullName)
		if caller == nil {
			panic(fmt.Sprintf("没有找到Caller : %s !", methodFullName))
		}
		routeFactory, ok := manager.routeFactories[method.Name]
		if ok {
			err := routeFactory(party, strings.ToLower(fmt.Sprintf("/%s/%s", servicePath, method.Name)), method.Type, caller)
			if err != nil {
				panic(err.Error())
			}
		}
	}
}
