// Package service 业务逻辑层
package service

import (
	"fmt"
	"server/common"
	"server/modules/user/vo"
	"server/modules/yx/dto"
	yxDto "server/modules/yx/dto"
	"server/modules/yx/entity"
	"server/modules/yx/mapper"
	"strings"
	"time"

	"github.com/google/uuid"
)

type YxCalculationMajorService struct {
	historyMajorEnrollService      *YxHistoryMajorEnrollService
	mapper                         *mapper.YxCalculationMajorMapper
	historyScoreControlLineService *YxHistoryScoreControlLineService
}

func (s *YxCalculationMajorService) RecommendMajorList(schoolMajorQuery yxDto.SchoolMajorQuery) ([]yxDto.UserMajorDTO, int64, dto.ProbabilityCountDTO, error) {
	if schoolMajorQuery.UserScoreVO.ProfessionalCategory == "" {
		return nil, 0, dto.ProbabilityCountDTO{}, fmt.Errorf("专业类型错误")
	}
	if schoolMajorQuery.Batch != "" {
		schoolMajorQuery.Batch = strings.ReplaceAll(schoolMajorQuery.Batch, "批", "")
	}
	// if len(schoolMajorQuery.MajorTypeChildren) > 0 && "高职高专" != schoolMajorQuery.Batch {
	// 	if "表演类" == schoolMajorQuery.MajorType {

	// 	}
	// }
	calculationMajors, total, probCount, err := s.mapper.FindRecommendList(schoolMajorQuery)
	if err != nil {
		return nil, 0, dto.ProbabilityCountDTO{}, err
	}

	// 为专业列表添加历史数据
	startTime := time.Now()
	err = s.UserMajorDTOGetHistory(&calculationMajors)
	endTime := time.Now()
	// 执行时长
	queryCostTime := endTime.Sub(startTime)
	fmt.Printf("  历史数据查询耗时：%v\n", queryCostTime)
	if err != nil {
		return nil, 0, dto.ProbabilityCountDTO{}, err
	}

	return calculationMajors, total, probCount, nil
}

func (s *YxCalculationMajorService) BatchCreateBySchoolMajorDTO(tableName string, items []dto.SchoolMajorDTO, scoreID string) error {
	entities := make([]entity.YxCalculationMajor, 0, len(items))
	now := time.Now()
	for _, item := range items {
		// 构建 OtherScoreLimitation
		var otherScoreLimitation strings.Builder
		if item.ChineseScoreLimitation > 0 {
			otherScoreLimitation.WriteString(fmt.Sprintf("语文成绩不低于%.1f分,", item.ChineseScoreLimitation))
		}
		if item.EnglishScoreLimitation > 0 {
			otherScoreLimitation.WriteString(fmt.Sprintf("外语成绩不低于%.1f分,", item.EnglishScoreLimitation))
		}
		if item.CulturalScoreLimitation > 0 {
			otherScoreLimitation.WriteString(fmt.Sprintf("文化成绩不低于%.1f分,", item.CulturalScoreLimitation))
		}
		if item.ProfessionalScoreLimitation > 0 {
			otherScoreLimitation.WriteString(fmt.Sprintf("专业成绩不低于%.1f分,", item.ProfessionalScoreLimitation))
		}
		otherScoreLimitationStr := otherScoreLimitation.String()
		if len(otherScoreLimitationStr) > 0 {
			otherScoreLimitationStr = otherScoreLimitationStr[:len(otherScoreLimitationStr)-1]
		}

		entities = append(entities, entity.YxCalculationMajor{
			ScoreID:                       scoreID,
			SchoolCode:                    item.SchoolCode,
			MajorCode:                     item.MajorCode,
			MajorName:                     item.MajorName,
			EnrollmentCode:                item.EnrollmentCode,
			Tuition:                       item.Tuition,
			Detail:                        item.Detail,
			Category:                      item.Category,
			RulesEnrollProbability:        item.RulesEnrollProbability,
			Batch:                         item.Batch,
			StudentOldConvertedScore:      item.StudentScore,
			StudentConvertedScore:         item.StudentConvertedScore,
			EnrollProbability:             item.EnrollProbability,
			ProbabilityOperator:           item.ProbabilityOperator,
			CreateTime:                    now,
			MajorType:                     item.MajorType,
			MajorTypeChild:                item.MajorTypeChild,
			PlanNum:                       item.PlanNum,
			MainSubjects:                  item.MainSubjects,
			Limitation:                    item.Limitation,
			OtherScoreLimitation:          otherScoreLimitationStr,
			RulesEnrollProbabilitySx:      item.RulesEnrollProbabilitySx,
			Kslx:                          item.Kslx,
			PrivateStudentConvertedScore:  item.PrivateStudentScore,
			PrivateRulesEnrollProbability: item.PrivateRulesEnrollProbability,
			PrivateProbabilityOperator:    item.PrivateProbabilityOperator,
			State:                         item.State,
		})
	}
	return s.BatchCreate(tableName, entities)
}

func NewYxCalculationMajorService() *YxCalculationMajorService {
	return &YxCalculationMajorService{
		historyMajorEnrollService:      NewYxHistoryMajorEnrollService(),
		mapper:                         mapper.NewYxCalculationMajorMapper(),
		historyScoreControlLineService: NewYxHistoryScoreControlLineService(),
	}
}

func (s *YxCalculationMajorService) List(page, size int) ([]entity.YxCalculationMajor, int64, error) {
	return s.mapper.FindAll(page, size)
}

func (s *YxCalculationMajorService) GetByID(id string) (*entity.YxCalculationMajor, error) {
	return s.mapper.FindByID(id)
}

func (s *YxCalculationMajorService) Create(item *entity.YxCalculationMajor) error {
	item.ID = uuid.New().String()
	return s.mapper.Create(item)
}

func (s *YxCalculationMajorService) Update(item *entity.YxCalculationMajor) error {
	return s.mapper.Update(item)
}

func (s *YxCalculationMajorService) UpdateFields(id string, fields map[string]interface{}) error {
	return s.mapper.UpdateFields(id, fields)
}

func (s *YxCalculationMajorService) Delete(id string) error {
	return s.mapper.Delete(id)
}

func (s *YxCalculationMajorService) GetByScoreID(scoreID string) ([]entity.YxCalculationMajor, error) {
	return s.mapper.FindByScoreID(scoreID)
}

func (s *YxCalculationMajorService) BatchCreate(tableName string, items []entity.YxCalculationMajor) error {
	for i := range items {
		items[i].ID = uuid.New().String()
	}
	return s.mapper.BatchCreate(tableName, items, 100)
}

func (s *YxCalculationMajorService) BatchUpdate(items []entity.YxCalculationMajor) error {
	return s.mapper.BatchUpdate(items)
}

func (s *YxCalculationMajorService) BatchUpsert(items []entity.YxCalculationMajor, updateColumns []string) error {
	for i := range items {
		if items[i].ID == "" {
			items[i].ID = uuid.New().String()
		}
	}
	return s.mapper.BatchUpsert(items, updateColumns)
}

func (s *YxCalculationMajorService) BatchDelete(ids []string) error {
	return s.mapper.BatchDelete(ids)
}

func (s *YxCalculationMajorService) DeleteByScoreID(scoreID string) error {
	return s.mapper.DeleteByScoreID(scoreID)
}

// 函数名 根据用户查询类型获取专业列表
// 详细描述（可选）
//
// 参数说明:
//
//		professionalCategory - 专业分类
//		cognitioPolyclinic - 文理文科
//	 	professionalCategoryChildren - 专业分类子项
//
// 返回值说明:
//
//	返回值类型 - 返回值描述
func (s *YxCalculationMajorService) ListByUserQueryType(professionalCategory string, cognitioPolyclinic string,
	professionalCategoryChildren []string) ([]dto.SchoolMajorDTO, error) {
	// 构造查询条件
	query := dto.SchoolMajorQuery{
		MajorType: professionalCategory,
		Category:  cognitioPolyclinic,
		// MainSubjects: "器乐",
		// MajorTypeChildren: []string{
		// 	"音乐教育",
		// },
	}

	// 执行院校查询
	majorItems, err := mapper.NewYxSchoolMajorMapper().SelectSchoolMajor(query)
	if err != nil {
		return nil, err
	}
	// 分别收集专业名称和院校代码集合（去重）
	majorNameSet := make(map[string]bool)
	schoolCodeSet := make(map[string]bool)
	years := common.OldYearList
	for _, dto := range majorItems {
		majorNameSet[dto.MajorName] = true
		schoolCodeSet[dto.SchoolCode] = true
	}
	// 转换为切片用于查询
	majorNames := make([]string, 0, len(majorNameSet))
	schoolCodes := make([]string, 0, len(schoolCodeSet))
	for name := range majorNameSet {
		majorNames = append(majorNames, name)
	}
	for code := range schoolCodeSet {
		schoolCodes = append(schoolCodes, code)
	}
	// 执行查询院校专业的历年数据 - 类似Java中的in查询
	historyItems, err := s.historyMajorEnrollService.ListBySchoolCodesAndMajorNames(
		schoolCodes,
		majorNames,
		query.Category,  // 文科/理科
		query.MajorType, // 专业类型
		years,           // 年份
	)

	if err != nil {
		return nil, err
	}

	// 构建历史数据映射：schoolCode_majorName_batch_year -> historyItem
	allHistoryMajorEnrollMap := make(map[string]entity.YxHistoryMajorEnroll)
	for _, historyItem := range historyItems {
		key := historyItem.SchoolCode + "_" + historyItem.MajorName + "_" + historyItem.Batch + "_" + historyItem.Year
		allHistoryMajorEnrollMap[key] = historyItem
	}
	// 将历史数据填充到每个专业数据中
	for i, majorItem := range majorItems {
		// 为每个majorItem创建独立的历史数据映射
		historyMap := make(map[string]dto.YxHistoryMajorEnrollDTO)

		for _, year := range years {
			key := majorItem.SchoolCode + "_" + majorItem.MajorName + "_" + majorItem.Batch + "_" + year
			if historyItem, ok := allHistoryMajorEnrollMap[key]; ok {
				// 类型转换：entity -> dto
				dtoItem := dto.YxHistoryMajorEnrollDTO{
					Year:                   historyItem.Year,
					EnrollmentCode:         historyItem.EnrollmentCode,
					RulesEnrollProbability: historyItem.RulesEnrollProbability,
					ProbabilityOperator:    historyItem.ProbabilityOperator,
					AdmissionLine:          historyItem.AdmissionLine,
					ControlLine:            historyItem.ControlLine,
					// 复制其他需要的字段
				}
				historyMap[year] = dtoItem
			}
		}
		majorItems[i].HistoryMajorEnrollMap = historyMap
	}

	return majorItems, nil
}

func (s *YxCalculationMajorService) UserMajorDTOGetHistory(userMajorDTOList *[]dto.UserMajorDTO) error {
	if len(*userMajorDTOList) > 0 {
		// 分别收集专业名称和院校代码集合（去重）
		majorNameSet := make(map[string]bool)
		schoolCodeSet := make(map[string]bool)
		years := common.OldYearList
		for _, dto := range *userMajorDTOList {
			majorNameSet[dto.MajorName] = true
			schoolCodeSet[dto.SchoolCode] = true
		}
		// 转换为切片用于查询
		majorNames := make([]string, 0, len(majorNameSet))
		schoolCodes := make([]string, 0, len(schoolCodeSet))
		for name := range majorNameSet {
			majorNames = append(majorNames, name)
		}
		for code := range schoolCodeSet {
			schoolCodes = append(schoolCodes, code)
		}
		// 执行查询院校专业的历年数据 - 类似Java中的in查询
		historyItems, err := s.historyMajorEnrollService.ListBySchoolCodesAndMajorNames(
			schoolCodes,
			majorNames,
			(*userMajorDTOList)[0].Category,  // 文科/理科
			(*userMajorDTOList)[0].MajorType, // 专业类型
			years,                            // 年份
		)

		if err != nil {
			return nil
		}

		// 构建历史数据映射：schoolCode_majorName_batch_year -> historyItem
		allHistoryMajorEnrollMap := make(map[string]entity.YxHistoryMajorEnroll)
		for _, historyItem := range historyItems {
			key := historyItem.SchoolCode + "_" + historyItem.MajorName + "_" + historyItem.Batch + "_" + historyItem.Year
			allHistoryMajorEnrollMap[key] = historyItem
		}
		// 将历史数据填充到每个专业数据中
		for i, majorItem := range *userMajorDTOList {
			// 为每个majorItem创建独立的历史数据映射
			historyMap := make(map[string]dto.YxHistoryMajorEnrollDTO)

			for _, year := range years {
				key := majorItem.SchoolCode + "_" + majorItem.MajorName + "_" + majorItem.Batch + "_" + year
				if historyItem, ok := allHistoryMajorEnrollMap[key]; ok {
					// 类型转换：entity -> dto
					dtoItem := dto.YxHistoryMajorEnrollDTO{
						Year:                   historyItem.Year,
						EnrollmentCode:         historyItem.EnrollmentCode,
						RulesEnrollProbability: historyItem.RulesEnrollProbability,
						ProbabilityOperator:    historyItem.ProbabilityOperator,
						AdmissionLine:          historyItem.AdmissionLine,
						ControlLine:            historyItem.ControlLine,
						// 复制其他需要的字段
					}
					historyMap[year] = dtoItem
				}
			}
			(*userMajorDTOList)[i].HistoryMajorEnrollMap = historyMap
		}
	}
	return nil
}

// 函数名 给专业列表计算录取率
// 详细描述（可选）
//
// 参数说明:
//
//		schoolMajorDTOList - 专业列表
//		professionalCategory - 专业分类
//		cognitioPolyclinic - 文理文科
//	 	professionalCategoryChildren - 专业分类子项
//
// 返回值说明:
//
//	返回值类型 - 返回值描述
func (s *YxCalculationMajorService) CheckEnrollProbability(schoolMajorDTOList *[]dto.SchoolMajorDTO, userScoreVO vo.UserScoreVO) error {

	professionalCategory := userScoreVO.ProfessionalCategory
	if "表演类" == professionalCategory {
		// TODO: biaoyanService
	} else if "音乐类" == professionalCategory {
		// TODO: musicService
	} else {
		s.betaRecommendMajorListSetEnrollProbability(schoolMajorDTOList, userScoreVO)
	}

	return nil
}

// betaRecommendMajorListSetEnrollProbability 美术与设计类，书法类，体育类 按这个走 获取录取率
func (s *YxCalculationMajorService) betaRecommendMajorListSetEnrollProbability(recommendMajorList *[]dto.SchoolMajorDTO, userScoreVO vo.UserScoreVO) {
	if recommendMajorList == nil || len(*recommendMajorList) == 0 {
		return
	}
	professionalCategory := userScoreVO.ProfessionalCategory
	nowBatch := "本科" // TODO 默认为本科，需根据实际情况获取，Java中是从 userScore 获取，这里 VO 中似乎没有 Batch? 假设为本科或从 VO 获取
	// userScoreVO.Batch? 检查 VO 定义
	// 假设 userScoreVO 没有 Batch，需要确认。Entity YxUserScore 有 Batch。VO 可能需要补充。
	// 暂时假设为 "本科" 或 ""

	// 获取省控线 Map
	historyScoreControlLineMap, err := s.historyScoreControlLineService.MapsBatchByProfessionalCategoryOfYear(common.NowYear, professionalCategory, userScoreVO.CognitioPolyclinic)
	if err != nil {
		// Log error
		return
	}

	culturalScore := userScoreVO.CulturalScore
	professionalScore := userScoreVO.ProfessionalScore

	for i := range *recommendMajorList {
		item := &(*recommendMajorList)[i]

		rulesEnrollProbability := item.PrivateRulesEnrollProbability
		probabilityOperator := item.PrivateProbabilityOperator

		// 获取对应批次的省控线
		controlLineData, ok := historyScoreControlLineMap[item.Batch]
		if !ok {
			// 尝试默认批次
			if val, okDefault := historyScoreControlLineMap["本科"]; okDefault {
				controlLineData = val
			} else {
				continue // 没有省控线无法计算
			}
		}

		culturalControlLine := controlLineData.CulturalScore
		specialControlLine := controlLineData.SpecialScore

		if rulesEnrollProbability == "" {
			continue
		}

		// 补全 probabilityOperator 逻辑
		if rulesEnrollProbability == "文过专排" && probabilityOperator == "" {
			probabilityOperator = "文*0+专*1"
		} else if rulesEnrollProbability == "专过文排" && probabilityOperator == "" {
			probabilityOperator = "文*1+专*0"
		}

		if probabilityOperator == "" {
			item.EnrollProbability = common.Number5
			continue
		}

		// 判断其他录取要求
		if !OtherScoreJudge(professionalScore, userScoreVO, *item) {
			item.EnrollProbability = common.Number0
			continue
		}

		// 25年专业录取原则变动 (体育类特殊逻辑，硬编码 ID 列表)
		if item.MajorType == "体育类" {
			specialSchoolCodes := []string{"6530", "6085", "6110", "6065", "6050"}
			isSpecial := false
			for _, code := range specialSchoolCodes {
				if item.SchoolCode == code {
					isSpecial = true
					break
				}
			}
			if isSpecial {
				item.EnrollProbability = common.Number0
				continue
			}
		}

		// 判断是否过省控线
		if !CrossingControlLine(rulesEnrollProbability, culturalScore, professionalScore, culturalControlLine, specialControlLine) {
			item.EnrollProbability = common.Number0
			continue
		}

		// 计算学生折合分
		studentScore := ConvertIntoScore(rulesEnrollProbability, culturalScore, professionalScore, probabilityOperator)
		item.PrivateStudentScore = studentScore
		item.StudentScore = studentScore // 展示用

		// 权限检查
		if !HasComputeEnrollProbabilityPermissions(nowBatch, item.Batch) {
			item.EnrollProbability = common.Number0
			continue
		}

		// 录取方式计算
		if common.CulturalControlLineGuoMain == rulesEnrollProbability {
			if len(item.HistoryMajorEnrollList) == 0 {
				item.EnrollProbability = common.Number0
				continue
			}
			item.EnrollProbability = (studentScore * item.HistoryMajorEnrollList[0].AdmissionLine) * common.Number0p75
			if studentScore >= item.HistoryMajorEnrollList[0].AdmissionLine {
				item.EnrollProbability *= common.Number0p5
			}
			continue
		} else {
			// 当前年省控线 折合后
			nowYearProvincialControlLine := ConvertIntoScore(rulesEnrollProbability, culturalControlLine, specialControlLine, probabilityOperator)
			if nowYearProvincialControlLine <= 0 {
				item.EnrollProbability = common.Number0
				continue
			}

			// 历年分差
			diffMap := ComputeHistoryMajorEnrollScoreLineDifferenceWithRulesEnrollProbability(item.MajorType, rulesEnrollProbability, probabilityOperator, item.HistoryMajorEnrollMap)
			historyThreeYearDiff := diffMap["scoreDifference"].(float64)

			if historyThreeYearDiff == 0 {
				item.EnrollProbability = common.Number0
				continue
			}

			// 当前年线差
			nowYearDiff := studentScore - nowYearProvincialControlLine

			// 计算录取率
			enrollProbability := CommonCheckEnrollProbability(nowYearDiff, historyThreeYearDiff)
			item.EnrollProbability = CommonCheckEnrollProbabilityBeilv(enrollProbability)
		}
	}

	// log time...
}
