// Package router ...
//
// Description : router ...
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 2025-10-30 15:39
package router

import (
	"errors"
	"reflect"

	"git.zhangdeman.cn/zhangdeman/gin/logger"
	"git.zhangdeman.cn/zhangdeman/gin/util"
	pkgLogger "git.zhangdeman.cn/zhangdeman/logger"
	"github.com/gin-gonic/gin"
)

// GetCommonParam 获取公共参数
type GetCommonParam func(ctx *gin.Context) (any, error)

// AddCommonParamRule 添加公共参数注入规则
func (s *server) AddCommonParamRule(fieldName string, getParamFunc GetCommonParam) {
	s.commonParam[fieldName] = getParamFunc
}

// AddCommonParamRules 批量添加公共参数注入规则
func (s *server) AddCommonParamRules(rules map[string]GetCommonParam) {
	for fieldName, rule := range rules {
		s.AddCommonParamRule(fieldName, rule)
	}
}

// injectCommonParam 注入公共参数
func (s *server) injectCommonParam(ctx *gin.Context, formValue any) error {
	innerCtx := util.GinCtxToContext(ctx)
	var (
		val              any
		err              error
		reflectFormValue reflect.Value
		reflectType      reflect.Type
		ok               bool
	)

	if reflectFormValue, ok = formValue.(reflect.Value); !ok {
		reflectFormValue = reflect.ValueOf(formValue)
		reflectType = reflect.TypeOf(formValue)
	} else {
		reflectType = reflectFormValue.Type()
	}
	if reflectType.Kind() == reflect.Ptr {
		reflectType = reflectType.Elem()
	}

	fieldTable := map[string]bool{}
	fieldNum := reflectType.NumField()
	for i := 0; i < fieldNum; i++ {
		if reflectType.Field(i).Anonymous && // 是匿名字段, 再做一次解析
			((reflectType.Field(i).Type.Kind() == reflect.Ptr && reflectType.Field(i).Type.Kind() == reflect.Struct) || // 结构体指针
				reflectType.Field(i).Type.Kind() == reflect.Struct) { // 结构体
			anonymousFieldType := reflectType.Field(i).Type
			if anonymousFieldType.Kind() == reflect.Ptr {
				anonymousFieldType = anonymousFieldType.Elem()
			}
			for j := 0; j < anonymousFieldType.NumField(); j++ {
				fieldTable[anonymousFieldType.Field(j).Name] = true
			}
		} else {
			// 提取全部结构体字段
			fieldTable[reflectType.Field(i).Name] = true
		}
	}
	for fieldName, getParamFunc := range s.commonParam {
		if _, ok = fieldTable[fieldName]; !ok {
			// 结构体字段未配置自动注入
			logger.Instance.Debug("当前结构体不包含指定字段, 忽略执行", pkgLogger.NewLogData(innerCtx, logger.RecordType, logger.CodeInjectCommonParam, map[string]any{
				"field_name": fieldName,
				"struct":     reflectFormValue.Elem().Type().String(),
			}).ToFieldList()...)
			continue
		}
		if reflectFormValue.Type().Kind() == reflect.Ptr {
			reflectFormValue = reflectFormValue.Elem()
		}
		fieldValue := reflectFormValue.FieldByName(fieldName)
		if !fieldValue.IsZero() {
			// 表单次数不为空, 说明从参数中传递, 不做覆盖填充
			logger.Instance.Debug("指定字段已赋值, 不做重新覆盖填充处理, 跳过", pkgLogger.NewLogData(innerCtx, logger.RecordType, logger.CodeInjectCommonParam, map[string]any{
				"field_name":       fieldName,
				"struct":           reflectFormValue.Elem().Type().String(),
				"input_form_value": fieldValue.Interface(),
			}).ToFieldList()...)
			continue
		}
		if val, err = getParamFunc(ctx); nil != err {
			logger.Instance.Error("获取公共结构体字段参数值失败", pkgLogger.NewLogData(innerCtx, logger.RecordType, logger.CodeInjectCommonParam, map[string]any{
				"field_name": fieldName,
				"err_msg":    err.Error(),
			}).ToFieldList()...)
			return err
		}
		if !fieldValue.CanSet() {
			logDataList := pkgLogger.NewLogData(util.GinCtxToContext(ctx), logger.RecordType, logger.CodeInjectCommonParam, map[string]any{
				"field_name": fieldName,
				"field_type": fieldValue.Type().String(),
			})
			logger.Instance.Error("结构体字段不可设置值", logDataList.ToFieldList()...)
			return errors.New(fieldName + ": 结构体字段不可设置值")
		}
		reflectVal := reflect.ValueOf(val)
		if reflectVal.Type() != fieldValue.Type() {
			logDataList := pkgLogger.NewLogData(util.GinCtxToContext(ctx), logger.RecordType, logger.CodeInjectCommonParam, map[string]any{
				"field_name": fieldName,
				"field_type": fieldValue.Type().String(),
				"value_type": reflectVal.Type().String(),
			})
			logger.Instance.Error("返回数据类型与字段类型不一致", logDataList.ToFieldList()...)
			return errors.New(fieldName + ": 字段自动注入, 返回数据类型与字段类型不一致")
		}
		// 设置值
		fieldValue.Set(reflectVal)
	}
	return nil
}
