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

package container

import (
	"errors"
	"fmt"
	"reflect"
)

// 服务方法信息
type ServiceMethodInformation struct {
	// 方法名
	methodName string
	// 方法类型
	methodType Method
	// 调用器代理创建器列表
	callerBrokerBuilders []CallerBrokerBuilder
	// 路由创建器
	routerBuilder RouterBuilder
}

// 创建服务方法信息
// 参数
// 1.方法元数据
// 返回值:
// 1.服务方法信息
// 异常
// 1.方法类型不能为空
// 2.方法名不能为空
// 3.返回值数量错误
// 4.最后一个返回值类型错误
func NewServiceMethodInformation(method *reflect.Method) *ServiceMethodInformation {

	if method == nil {
		panic(fmt.Sprintf("方法类型不能为空!"))
	}
	methodName := method.Name
	methodType := method.Type
	if methodName == "" {
		panic(fmt.Sprintf("方法名不能为空!"))
	}
	if methodType.NumOut() < 1 || 2 < methodType.NumOut() {
		panic(fmt.Sprintf("返回值数量错误! 返回值数量: %d", methodType.NumOut()))
	}
	if methodType.Out(methodType.NumOut()-1) != errorType {
		panic(fmt.Sprintf("最后一个返回值类型错误! 类型:%s", methodType.Out(methodType.NumOut()-1)))
	}
	logBroker := NewLogBrokerBuilder("", methodName, "")
	err := logBroker.Check(methodType)
	if err != nil {
		panic(err.Error())
	}
	return &ServiceMethodInformation{methodName, methodType, []CallerBrokerBuilder{logBroker}, nil}
}

// 获取方法名
// 返回值:
// 1.方法名
func (info *ServiceMethodInformation) MethodName() string {
	return info.methodName
}

// 获取方法类型
// 返回值:
// 1.方法类型
func (info *ServiceMethodInformation) MethodType() Method {
	return info.methodType
}

// 添加调用器代理创建器
// 参数
// 1.调用器代理创建器
// 异常
// 1.调用器代理创建器不能设置为空
func (info *ServiceMethodInformation) AppendBrokerBuilder(callerBrokerBuilder CallerBrokerBuilder) {
	if callerBrokerBuilder == nil {
		panic(fmt.Sprintf("调用器代理创建器不能设置为空!"))
	}
	if err := callerBrokerBuilder.Check(info.methodType); err != nil {
		panic(err.Error())
	}
	info.callerBrokerBuilders = append(info.callerBrokerBuilders, callerBrokerBuilder)
}

// 获取路由创建器
// 返回值:
// 1.路由创建器
func (info *ServiceMethodInformation) RouterBuilder() RouterBuilder {
	return info.routerBuilder
}

// 设置路由创建器
// 参数
// 1.路由创建器
// 异常
// 1.路由创建器不能设置为空
// 2.已经设置路由创建器
func (info *ServiceMethodInformation) SetRouterBuilder(value RouterBuilder) {
	if value == nil {
		panic(fmt.Sprintf("路由创建器不能设置为空!"))
	}
	if info.routerBuilder != nil {
		panic(fmt.Sprintf("已经设置路由创建器!"))
	}
	info.routerBuilder = value
}

// 设置调用器代理创建器和路由创建器
// 参数
// 1.创建器集合
// 返回值:
// 1.错误
// 异常
// 1.路由创建器不能设置为空
// 2.已经设置路由创建器
// 3.调用器代理创建器不能设置为空
func (info *ServiceMethodInformation) SetBuilders(builders BuilderSet) {
	info.SetRouterBuilder(builders.RouterBuilder)
	if builders.CallerBrokerBuilders != nil {
		for _, brokerBuilder := range builders.CallerBrokerBuilders {
			info.AppendBrokerBuilder(brokerBuilder)
		}
	}
}

// 创建方法句柄
// 参数
// 1.当前会话上下文
// 2.服务实例
// 返回值:
// 1.方法句柄
// 2.错误
func (info *ServiceMethodInformation) BuildHandler(sessionContext *SessionContext, instance Instance) (*ServiceMethodHandler, error) {

	if sessionContext == nil {
		return nil, errors.New(fmt.Sprintf("会话上下文不能为空!"))
	}
	caller, err := instance.GetCaller(info.methodName)
	if err != nil {
		return nil, err
	}
	if caller == nil {
		return nil, errors.New(fmt.Sprintf("原始调用器不能为空!"))
	}
	for i := len(info.callerBrokerBuilders) - 1; i >= 0; i-- {
		brokerBuilder := info.callerBrokerBuilders[i]
		caller, err = brokerBuilder.Build(sessionContext, caller)
		if err != nil {
			return nil, err
		}
		if caller == nil {
			return nil, errors.New(fmt.Sprintf("第%d个调用器不能为空!", i+1))
		}
	}
	serviceMethodHandler, err := NewServiceMethodHandler(caller)
	if err != nil {
		return nil, err
	}
	return serviceMethodHandler, err
}
