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

package container

import (
	"LAPP_LF_MOM_BACKEND/web/models"
	"errors"
	"fmt"
	"github.com/kataras/iris/v12/context"
	"github.com/kataras/iris/v12/core/router"
	"reflect"
	"strings"
)

const (
	ServicesPackageName            = "services"
	ServiceNameSuffix              = "Service"
	PathSeparator                  = "/"
	HttpPost            HttpMethod = "POST"
	HttpPut             HttpMethod = "POU"
	HttpGet             HttpMethod = "Get"
	HttpDelete          HttpMethod = "DELETE"
)

var ServiceNameSuffixLength = len([]rune(ServiceNameSuffix))

type HttpMethod string

type (
	// 调用器
	// 参数
	// 1.参数列表
	// 返回值:
	// 1.返回值列表
	Caller = func([]reflect.Value) []reflect.Value
	// 调用器工厂
	// 参数
	// 1.会话标识
	// 2.用户信息
	// 返回值:
	// 1.调用器
	// 2.错误
	CallerFactory = func(string, *models.Usertab) (Caller, error)
	// 路由
	Router = context.Handler
	// 路由创建器
	// 参数
	// 1.会话管理器
	// 2.服务类型
	// 3.服务方法名
	// 3.服务方法类型
	// 返回值:
	// 1.HTTP请求方法
	// 2.附加路径
	// 3.路由
	// 4.错误
	RouterBuilder = func(CallerFactory, string, reflect.Type) (HttpMethod, string, Router, error)
)

// *SessionContext类型常量
var sessionContextType = reflect.TypeOf((*SessionContext)(nil))

// 空参数列表
var emptyParameters []reflect.Value

// Factory零值
var zeroOfFactory = Factory(reflect.ValueOf(nil))

// *error 类型常量
var errorType = reflect.TypeOf((*error)(nil)).Elem()

// *RequestContext类型常量
var RequestContextType = reflect.TypeOf((*RequestContext)(nil))

// 无会话(XORM会话)上下文
var ContextOfNoSession = NewNoSessionBrokerBuilder()

// 新会话(XORM会话)上下文
var ContextOfNewSession = NewNewSessionBrokerBuilder()

// 新事务代理创建器上下文
var ContextOfNewTransaction = NewNewTransactionBrokerBuilder()

//
//// 组件信息管理器
//var currentInformationManager = NewInformationManager()

// 解析组件工厂,返回:组件工厂Value,组件模块名,组件接口,错误
// 参数
// 1.工厂方法
// 返回值:
// 1.组件工厂
// 2.组件接口类型
// 异常:
// 1.工厂不能为空
// 2.工厂必须是func
// 3.工厂不能有参数
// 4.工厂必值需有返回值
// 5.工厂只能有一个返回值
// 6.工厂的返回值必需是interface
func parseFactory(factory interface{}) (Factory, Interface) {
	if factory == nil {
		panic(fmt.Sprintf("工厂不能为空!"))
	}
	valueOfFactory := reflect.ValueOf(factory)
	typeOfFactory := valueOfFactory.Type()
	if typeOfFactory.Kind() != reflect.Func {
		panic(fmt.Sprintf("工厂必须是func!"))
	}
	if typeOfFactory.NumIn() != 0 {
		panic(fmt.Sprintf("工厂不能有参数!"))
	}
	if typeOfFactory.NumOut() < 1 {
		panic(fmt.Sprintf("工厂必值需有返回值!"))
	}
	if typeOfFactory.NumOut() > 1 {
		panic(fmt.Sprintf("工厂只能有一个返回值!"))
	}
	if typeOfFactory.Out(0).Kind() != reflect.Interface {
		panic(fmt.Sprintf("工厂的返回值必需是interface!"))
	}
	componentType := typeOfFactory.Out(0)
	return Factory(valueOfFactory), componentType
}

// Caller相等性判断
// 参数
// 1.比较对象1
// 3.比较对象2
// 返回值:
// 1.判断结果
func CallerEqual(caller1 Caller, caller2 Caller) bool {
	if caller1 == nil {
		if caller2 == nil {
			return true
		} else {
			return false
		}
	} else {
		if caller2 == nil {
			return false
		} else {
			return reflect.ValueOf(caller1).Pointer() == reflect.ValueOf(caller2).Pointer()
		}
	}
}

var GlobalInformations = NewInformationManager()

// 注册路由
// 参数:
// 1.路由分组
// 2.组件信息管理器
// 3.事务句柄工厂
// 返回值:
// 1.错误
// 异常:
// 1.组件信息管理器不能为空
// 2.事务句柄工厂不能为空
// 3.服务不在包或他的子包之下
// 4.组件接口名称的后缀不正确
func RegisterRoutes(party router.Party, defaultRouterBuilder RouterBuilder, informationManager InformationManager, transactionHandlerFactory TransactionHandlerFactory) {
	sessionManager := NewSessionManager(informationManager, transactionHandlerFactory)
	groups := make(map[string][]*ServiceInformation, 10)
	for _, information := range informationManager.Items() {
		if serviceInformation, ok := information.(*ServiceInformation); ok {
			packagePath := serviceInformation.Interface().PkgPath()
			group, ok := groups[packagePath]
			if !ok {
				group = make([]*ServiceInformation, 0, 10)
			}
			groups[packagePath] = append(group, serviceInformation)
		}
		for packagePath, group := range groups {
			packageList := strings.Split(packagePath, PathSeparator)
			moudlePath := ""
			for index, packageName := range packageList {
				if strings.ToLower(packageName) == ServicesPackageName {
					moudlePath = strings.Join(packageList[index+1:], PathSeparator)
					break
				}
			}
			if moudlePath == "" {
				panic(fmt.Sprintf("包%s不在包%s或他的子包之下!", packagePath, ServicesPackageName))
			}
			moudleParty := party.Party(fmt.Sprintf("/%s", strings.ToLower(moudlePath)))
			for _, serviceInformation := range group {
				serviceType := serviceInformation.Interface()
				serviceName := serviceType.Name()
				if !strings.HasSuffix(serviceName, ServiceNameSuffix) {
					panic(fmt.Sprintf("组件%s接口名称的后缀不是%s!", serviceName, ServiceNameSuffix))
				}
				runesOfserviceName := []rune(serviceName)
				serviceParty := moudleParty.Party(fmt.Sprintf("/%s", strings.ToLower(string(runesOfserviceName[:len(runesOfserviceName)-ServiceNameSuffixLength]))))
				for _, serviceMethodInformation := range serviceInformation.Methods() {
					methodName := serviceMethodInformation.MethodName()
					routerBuilder := serviceMethodInformation.RouterBuilder()
					if routerBuilder == nil {
						routerBuilder = defaultRouterBuilder
					}

					var callerFactory = func(sessionId string, user *models.Usertab) (Caller, error) {
						session, err := sessionManager.GetSession(sessionId, user)
						if err != nil {
							return nil, err
						}
						serviceHandler, ok := session.Handlers().Handler(serviceType).(*ServiceHandler)
						if !ok {
							return nil, errors.New(fmt.Sprintf("竟然没找到服务组件句柄!"))
						}
						return serviceHandler.Method(methodName).Caller(), nil
					}

					serviceMethodName := fmt.Sprintf("%s.%s", serviceName, methodName)
					httpMethod, addedPath, irisRouter, err := routerBuilder(callerFactory, serviceMethodName, serviceMethodInformation.MethodType())
					if err != nil {
						panic(err.Error())
					}
					serviceParty.Handle(string(httpMethod), fmt.Sprintf("/%s", strings.ToLower(methodName)+addedPath), irisRouter)
				}
			}
		}
	}
}
