package dto

import (
	"errors"
)

// SaveScoreRequest 保存成绩请求
type SaveScoreRequest struct {
	CognitioPolyclinic                string             `json:"CognitioPolyclinic" binding:"required"`
	SubjectList                       []string           `json:"SubjectList" binding:"required"`
	ProfessionalCategory              string             `json:"ProfessionalCategory" binding:"required"`
	ProfessionalCategoryChildren      []string           `json:"ProfessionalCategoryChildren" binding:"required"`
	ProfessionalCategoryChildrenScore map[string]float64 `json:"ProfessionalCategoryChildrenScore" binding:"required"`
	ProfessionalScore                 *float64           `json:"ProfessionalScore" binding:"required"`
	CulturalScore                     *float64           `json:"CulturalScore" binding:"required"`
	EnglishScore                      *float64           `json:"EnglishScore" binding:"required"`
	ChineseScore                      *float64           `json:"ChineseScore" binding:"required"`
	Province                          string             `json:"Province" binding:"required"`
	CreateBy                          string
}

func (req *SaveScoreRequest) Validate() error {
	if req.CognitioPolyclinic != "文科" && req.CognitioPolyclinic != "理科" {
		return errors.New("考试类型必须是'物理组'或'历史组'")
	}

	if req.ProfessionalCategory == "表演类" || req.ProfessionalCategory == "音乐类" {
		if len(req.ProfessionalCategoryChildren) == 0 {
			return errors.New("表演类或音乐类必须至少选一个专业子级")
		}
	} else {
		req.ProfessionalCategoryChildren = []string{}
	}

	if len(req.SubjectList) > 3 {
		return errors.New("选考科目有且最多只能传三个值")
	}

	validSubjects := map[string]bool{"地理": true, "政治": true, "历史": true, "化学": true, "生物": true}
	for _, s := range req.SubjectList {
		if !validSubjects[s] {
			return errors.New("选考科目参数有误")
		}
	}
	if !isValidScore(*req.ProfessionalScore, 300) {
		return errors.New("统考成绩必须在0-300之间")
	}
	if !isValidScore(*req.CulturalScore, 750) {
		return errors.New("文化成绩必须在0-750之间")
	}
	if !isValidScore(*req.EnglishScore, 150) {
		return errors.New("英文成绩必须在0-150之间")
	}
	if !isValidScore(*req.ChineseScore, 150) {
		return errors.New("中文成绩必须在0-150之间")
	}
	// TODO 在这里判断一下 专业子级,如 表演类只有："服装表演", "戏剧影视表演", "戏剧影视导演"。音乐类只有：音乐表演声乐、音乐表演器乐、音乐教育。
	validProfessionalChildren := map[string]string{ // 子级 -> 父级分类
		"服装表演":   "表演类",
		"戏剧影视表演": "表演类",
		"戏剧影视导演": "表演类",
		"音乐表演声乐": "音乐类",
		"音乐表演器乐": "音乐类",
		"音乐教育":   "音乐类",
	}
	// 统计各分类的数量
	categoryCount := make(map[string]int)
	for childName, score := range req.ProfessionalCategoryChildrenScore {
		// 验证子级名称是否合法
		parentCategory, exists := validProfessionalChildren[childName]
		if !exists {
			return errors.New("不支持的专业子级: " + childName)
		}
		// 统计分类数量
		categoryCount[parentCategory]++
		// 验证分数范围
		if !isValidScore(score, 300) {
			return errors.New(childName + "成绩必须在0-300之间")
		}
	}
	// 分类数量限制，比如每类最多几个
	for category, count := range categoryCount {
		if category == "音乐类" {
			// 判断 子级是否包含 xx
			if req.ProfessionalCategoryChildrenScore["音乐表演声乐"] > 0 && req.ProfessionalCategoryChildrenScore["音乐表演器乐"] > 0 {
				return errors.New("音乐类子级不可同时选择'音乐表演声乐'和'音乐表演器乐'")
			}
		}
		if count > 3 { // 假设每类最多3个
			return errors.New(category + "最多只能有3个子级")
		}
		for _, key := range req.ProfessionalCategoryChildren {
			if req.ProfessionalCategoryChildrenScore[key] == 0 {
				return errors.New(key + "成绩不能为空")
			}
		}
	}

	// 专业子级和成绩数据一致性校验
	if err := req.validateProfessionalConsistency(); err != nil {
		return err
	}

	return nil
}

func (req *SaveScoreRequest) validateProfessionalConsistency() error {
	// 特殊情况：如果不需要专业子级，则两个都应该为空
	if len(req.ProfessionalCategoryChildren) == 0 {
		if len(req.ProfessionalCategoryChildrenScore) != 0 {
			return errors.New("未选择专业子级时，成绩数据应为空")
		}
		return nil
	}
	// 创建映射用于双向验证
	childrenMap := make(map[string]bool)
	for _, child := range req.ProfessionalCategoryChildren {
		if childrenMap[child] {
			return errors.New("专业子级 '" + child + "' 重复")
		}
		childrenMap[child] = true
	}
	// 验证长度一致
	if len(childrenMap) != len(req.ProfessionalCategoryChildrenScore) {
		return errors.New("专业子级列表与成绩数据数量不匹配")
	}
	// 双向验证一致性
	for childName := range req.ProfessionalCategoryChildrenScore {
		if !childrenMap[childName] {
			return errors.New("成绩数据中的专业子级 '" + childName + "' 未在选中列表中")
		}
	}
	for _, child := range req.ProfessionalCategoryChildren {
		if _, exists := req.ProfessionalCategoryChildrenScore[child]; !exists {
			return errors.New("选中的专业子级 '" + child + "' 缺少成绩数据")
		}
	}
	return nil
}

func isValidScore(score float64, max float64) bool {
	return score >= 0 && score <= max
}
