package service

import (
	"fmt"

	"github.com/linmadan/egglib-go/core/application"
	"github.com/xuri/excelize/v2"
	"gitlab.fjmaimaimai.com/allied-creation/performance/pkg/application/factory"
	"gitlab.fjmaimaimai.com/allied-creation/performance/pkg/application/staff_assess/adapter"
	"gitlab.fjmaimaimai.com/allied-creation/performance/pkg/application/staff_assess/query"
	"gitlab.fjmaimaimai.com/allied-creation/performance/pkg/domain"
	"gitlab.fjmaimaimai.com/allied-creation/performance/pkg/infrastructure/dao"
	"gitlab.fjmaimaimai.com/allied-creation/performance/pkg/log"
)

//员工绩效-项目管理

// 获取已被执行的周期列表
func (srv StaffAssessServeice) ListAllAssessCycle(companyid int) (map[string]interface{}, error) {
	transactionContext, err := factory.CreateTransactionContext(nil)
	if err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	if err := transactionContext.StartTransaction(); err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	defer func() {
		_ = transactionContext.RollbackTransaction()
	}()
	assessDao := dao.NewStaffAssessDao(map[string]interface{}{
		"transactionContext": transactionContext,
	})
	cycleList, err := assessDao.AllAssessCycleList(companyid)
	if err != nil {
		return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, "获取周期列表"+err.Error())
	}
	if err := transactionContext.CommitTransaction(); err != nil {
		return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
	}
	result := map[string]interface{}{
		"list": cycleList,
	}
	return result, nil

}

// 获取周期内的考核日期
func (srv StaffAssessServeice) ListAllAssessCycleDay(param *query.ListAssessCycleDay) (map[string]interface{}, error) {
	transactionContext, err := factory.CreateTransactionContext(nil)
	if err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	if err := transactionContext.StartTransaction(); err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	defer func() {
		_ = transactionContext.RollbackTransaction()
	}()
	assessDao := dao.NewStaffAssessDao(map[string]interface{}{
		"transactionContext": transactionContext,
	})
	cycleDayList, err := assessDao.AllAssessCycleDayList(param.CompanyId, param.CycleId)
	if err != nil {
		return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, "获取周期列表"+err.Error())
	}
	if err := transactionContext.CommitTransaction(); err != nil {
		return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
	}
	result := map[string]interface{}{
		"list": cycleDayList,
	}
	return result, nil
}

// 根据周期id和日期获取 员工填写评估内容
// 有过滤查看权限
func (srv StaffAssessServeice) ListUserAssessContentCycleDay(param *query.ListAssessContentCycleDay) (*adapter.ListUserAssessContent, error) {
	transactionContext, err := factory.CreateTransactionContext(nil)
	if err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	if err := transactionContext.StartTransaction(); err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	defer func() {
		_ = transactionContext.RollbackTransaction()
	}()

	hrbp, err := srv.getHRBP(transactionContext, param.CompanyId, param.OperaterId)
	if err != nil {
		return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
	}

	assessDao := dao.NewStaffAssessDao(map[string]interface{}{
		"transactionContext": transactionContext,
	})

	limit := param.PageSize
	offset := (param.PageNumber - 1) * limit
	cnt, err := assessDao.CountUserAssess(dao.SearchConditin1{
		CompanyId:      param.CompanyId,
		CycleId:        param.CycleId,
		BeginDay:       param.BeginDay,
		TargetUserName: param.TargetUserName,
		Limit:          5000,
		Offset:         0,
		OperaterId:     param.OperaterId,
		Hrbp:           hrbp,
	})
	if err != nil {
		return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, "统计总数"+err.Error())
	}
	contentList, err := assessDao.SearchUserAssessContent(dao.SearchConditin1{
		CompanyId:      param.CompanyId,
		CycleId:        param.CycleId,
		BeginDay:       param.BeginDay,
		TargetUserName: param.TargetUserName,
		Limit:          limit,
		Offset:         offset,
		OperaterId:     param.OperaterId,
		Hrbp:           hrbp,
	})
	if err != nil {
		return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, "获取数据列表"+err.Error())
	}
	if err := transactionContext.CommitTransaction(); err != nil {
		return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
	}
	log.Logger.Debug(fmt.Sprintf("获取到的数据列表%d", len(contentList)))
	//可变的表格列
	changeableHeader := []adapter.ListTableHeader{
		{Key: "targetUserName", Name: "姓名"}, //固定列
	}
	//过滤重复的列
	headerMap := map[string]string{}
	// 获取已经填报的内容
	changeableRows := map[string]map[string]interface{}{}
	tableSort := []string{} //确定列表行数据的顺序
	for i, v := range contentList {
		if _, ok := changeableRows[v.TargetUserId]; !ok {
			changeableRows[v.TargetUserId] = map[string]interface{}{}
			tableSort = append(tableSort, v.TargetUserId)
		}
		changeableRows[v.TargetUserId]["targetUserName"] = v.TargetUserName
		changeableRows[v.TargetUserId]["targetUserId"] = v.TargetUserId
		changeableRows[v.TargetUserId]["assessId"] = v.AssessId
		changeableRows[v.TargetUserId]["cycleId"] = v.CycleId
		changeableRows[v.TargetUserId]["beginDay"] = v.BeginDay
		if v.ContentId > 0 {
			name := fmt.Sprintf("%s-%s", v.Category, v.ContentName)
			key := fmt.Sprintf("k%d", i)
			if _, ok := headerMap[name]; !ok {
				changeableHeader = append(changeableHeader, adapter.ListTableHeader{
					Key: key, Name: name,
				})
				headerMap[name] = key
			}
			key = headerMap[name]
			changeableRows[v.TargetUserId][key] = v.Value
		}
	}
	list := []map[string]interface{}{}
	for _, v := range tableSort {
		for _, v2 := range changeableHeader {
			if _, ok := changeableRows[v][v2.Key]; ok {
				continue
			}
			changeableRows[v][v2.Key] = ""
		}
		list = append(list, changeableRows[v])
	}
	result := adapter.ListUserAssessContent{
		TableHeader: changeableHeader,
		Total:       cnt,
		List:        list,
	}
	return &result, nil
}

//员工绩效-项目管理-矩阵分析

func (srv StaffAssessServeice) AnalysisData(param *query.ListAssessContentCycleDay) (*adapter.AssessAnalysisResp, error) {
	transactionContext, err := factory.CreateTransactionContext(nil)
	if err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	if err := transactionContext.StartTransaction(); err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	defer func() {
		_ = transactionContext.RollbackTransaction()
	}()

	hrbp, err := srv.getHRBP(transactionContext, param.CompanyId, param.OperaterId)
	if err != nil {
		return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
	}
	assessDao := dao.NewStaffAssessDao(map[string]interface{}{
		"transactionContext": transactionContext,
	})
	contentList, err := assessDao.SearchUserAssessContent(dao.SearchConditin1{
		CompanyId:      param.CompanyId,
		CycleId:        param.CycleId,
		BeginDay:       param.BeginDay,
		TargetUserName: param.TargetUserName,
		Limit:          9000,
		Offset:         0,
		OperaterId:     param.OperaterId,
		Hrbp:           hrbp,
	})
	if err != nil {
		return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, "获取数据列表"+err.Error())
	}
	if err := transactionContext.CommitTransaction(); err != nil {
		return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
	}
	log.Logger.Debug(fmt.Sprintf("获取到的数据列表%d", len(contentList)))

	var groupList []string                               //评估指标项列表
	var uncompleteItems []string                         //未完成填写评估的员工
	completeUser := map[string]struct{}{}                //完成填写评估的员工
	completeItems := map[string]adapter.AssessComplete{} //已完成填写的评估内容

	for _, v := range contentList {
		if v.ContentId == 0 {
			uncompleteItems = append(uncompleteItems, v.TargetUserName)
			continue
		}
		completeUser[v.TargetUserId] = struct{}{}
		key := v.Category + "-" + v.ContentName

		if _, ok := completeItems[key]; !ok {
			groupList = append(groupList, key)
			//初始化数据结构
			completeItems[key] = adapter.AssessComplete{
				GroupKey:    key,
				Items:       []string{},
				UserItem:    map[string][]string{},
				PercentItem: map[string]string{},
				CountItem:   map[string]int{},
			}
		}
		completeItem := completeItems[key]
		if v.Rule.Type == domain.EvaluationTypeRating {
			//提取出所有可选的评级
			for _, v2 := range v.Rule.Rating.Levels {
				if _, ok := completeItem.CountItem[v2.Code]; !ok {
					completeItem.CountItem[v2.Code] = 0
					completeItem.PercentItem[v2.Code] = ""
					completeItem.UserItem[v2.Code] = []string{}
					completeItem.Items = append(completeItem.Items, v2.Code)
				}
			}
		}
		if v.Rule.Type == domain.EvaluationTypeScore {
			for _, v2 := range v.Rule.Score.Levels {
				//提取出所有可选的评级
				if _, ok := completeItem.CountItem[v2.Code]; !ok {
					completeItem.CountItem[v2.Code] = 0
					completeItem.PercentItem[v2.Code] = ""
					completeItem.UserItem[v2.Code] = []string{}
					completeItem.Items = append(completeItem.Items, v2.Code)
				}
			}
		}
		//根据填写的评级填充数据
		completeItem.TotalUser = completeItem.TotalUser + 1
		completeItem.CountItem[v.LevelValue] = completeItem.CountItem[v.LevelValue] + 1
		percentSum := float64(completeItem.CountItem[v.LevelValue]) / float64(completeItem.TotalUser) * 100
		completeItem.PercentItem[v.LevelValue] = fmt.Sprintf("%.2f %%", percentSum)
		completeItem.UserItem[v.LevelValue] = append(completeItem.UserItem[v.LevelValue], v.TargetUserName)
		completeItems[key] = completeItem
	}
	result := adapter.AssessAnalysisResp{
		GroupList:  groupList,
		Uncomplete: uncompleteItems,
		Complete:   completeItems,
		UserCount: map[string]int{
			"total":      len(uncompleteItems) + len(completeUser),
			"uncomplete": len(uncompleteItems),
			"complete":   len(completeUser),
		},
	}
	return &result, nil
}

// 员工绩效-综合管理-导出绩效-个人
func (srv StaffAssessServeice) ExportUserAssess2(param *query.ExportUserAssess2Commad) (*excelize.File, error) {
	transactionContext, err := factory.CreateTransactionContext(nil)
	if err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	if err := transactionContext.StartTransaction(); err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	defer func() {
		_ = transactionContext.RollbackTransaction()
	}()
	hrbp, err := srv.getHRBP(transactionContext, param.CompanyId, param.OperatorId)
	if err != nil {
		return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
	}
	assessDao := dao.NewStaffAssessDao(map[string]interface{}{
		"transactionContext": transactionContext,
	})
	// 获取所有的评估项
	categoryNameList, err := assessDao.SearchContentCategoryName(param.CompanyId, param.CycleId, param.OperatorId, hrbp, param.ExportUserId)
	if err != nil {
		return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
	}
	//获取员工填写的评估
	userAssessList, err := assessDao.ExportDataUserAssess2(
		param.CompanyId,
		param.CycleId,
		param.OperatorId,
		hrbp,
		param.ExportUserId,
	)
	if err != nil {
		return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
	}
	if err := transactionContext.CommitTransaction(); err != nil {
		return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
	}
	eData := newExportData()
	eData.setCategoryNameList(categoryNameList)
	eData.setData(userAssessList)
	xlsxFile := excelize.NewFile()
	//设置默认的第一个sheet
	sheetIndex := xlsxFile.GetActiveSheetIndex()
	firstSheetName := xlsxFile.GetSheetName(sheetIndex)
	cycleName := ""
	if len(userAssessList) > 0 {
		cycleName = userAssessList[0].CycleName
	}
	//填入excel 文件
	for _, v := range eData.userName {
		// 根据员工名称 添加一个sheet
		xlsxFile.NewSheet(v)
		//填写前4行数据
		tableHeader, ok := eData.tableHeader[v]
		if !ok {
			continue
		}
		xlsxFile.SetCellStr(v, "B2", v)
		xlsxFile.MergeCell(v, "B2", "B4")
		//填充第一列数据
		xlsxFile.SetCellStr(v, "A1", tableHeader.Name)
		xlsxFile.SetCellStr(v, "A2", cycleName)
		xlsxFile.MergeCell(v, "A2", "A4")
		xlsxFile.SetCellStr(v, "A5", "权重")
		xlsxFile.MergeCell(v, "A5", "B5")
		xlsxFile.SetCellStr(v, "A6", "评估标准")
		xlsxFile.MergeCell(v, "A6", "B6")
		//日期
		dayList := eData.userDayMap[v]
		for ii, vv := range dayList {
			//填写在第几行
			axisNum := 7 + 3*ii
			axis := fmt.Sprintf("A%d", axisNum)
			xlsxFile.SetCellStr(v, axis, vv)
			axisEnd := fmt.Sprintf("B%d", axisNum+2)
			xlsxFile.MergeCell(v, axis, axisEnd) //单元格高度按三个单元格合并
		}
		allColNum := 0 //计算总共有多少列
		//第一行
		for _, v2 := range tableHeader.Child {

			//第二行
			for _, v3 := range v2.Child {
				//第三行
				for _, v4 := range v3.Child {
					allColNum++
					//按列填充数据
					colName, _ := excelize.ColumnNumberToName(allColNum + 2) //第3列开始
					xlsxFile.SetCellStr(v, colName+"2", v2.Name)             //分类
					xlsxFile.SetCellStr(v, colName+"3", v3.Name)             //加分项 得分项
					xlsxFile.SetCellStr(v, colName+"4", v4.Name)             // 评估项名称
					//权重 填写第5行数据
					k23 := eData.data23Key(v, v2.Name, v3.Name, v4.Name)
					xlsxFile.SetCellStr(v, colName+"5", eData.data3[k23])
					//评估标准 填写第6行数据
					xlsxFile.SetCellStr(v, colName+"6", eData.data2[k23])
					//按日期填充评估的填写的值
					for i5, v5 := range dayList {
						k1 := eData.dataKey(v, v5, v2.Name, v3.Name, v4.Name)
						//填写在第几行
						axisNum := 7 + 3*i5
						axis := fmt.Sprintf("%s%d", colName, axisNum)
						if d, ok := eData.data[k1]; ok {
							xlsxFile.SetCellStr(v, axis, d.String())
						}
						//单元格高度按三个单元格合并
						axisEnd := fmt.Sprintf("%s%d", colName, axisNum+2)
						xlsxFile.MergeCell(v, axis, axisEnd)
					}
				}
			}
		}
		//
		colName, _ := excelize.ColumnNumberToName(allColNum + 2)
		xlsxFile.MergeCell(v, "A1", fmt.Sprintf("%s1", colName))
	}
	//删除默认的第一个sheet
	xlsxFile.DeleteSheet(firstSheetName)
	return xlsxFile, nil
}

// 获取所有的评估的指标
func (srv StaffAssessServeice) QueryPerformanceIndicator(param *query.ListAssessContentCycleDay) (map[string]interface{}, error) {
	transactionContext, err := factory.CreateTransactionContext(nil)
	if err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	if err := transactionContext.StartTransaction(); err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	defer func() {
		_ = transactionContext.RollbackTransaction()
	}()

	hrbp, err := srv.getHRBP(transactionContext, param.CompanyId, param.OperaterId)
	if err != nil {
		return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
	}
	assessDao := dao.NewStaffAssessDao(map[string]interface{}{
		"transactionContext": transactionContext,
	})

	contentItems, err := assessDao.SearchUserAssessContentItem(dao.SearchConditin1{
		CompanyId:  param.CompanyId,
		CycleId:    param.CycleId,
		BeginDay:   param.BeginDay,
		OperaterId: param.OperaterId,
		Hrbp:       hrbp,
	})
	if err != nil {
		return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, "统计总数"+err.Error())
	}
	if err := transactionContext.CommitTransaction(); err != nil {
		return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
	}

	headerList := HeaderLevel{
		Name:   "",
		Filter: map[string]int{},
		Child:  []HeaderLevel{},
	}
	for _, v := range contentItems {
		child := headerList.addChild(v.Category)
		child.addChild(v.Name)
	}
	result := map[string]interface{}{
		"headerList": headerList.Child,
	}
	return result, nil
}

// 员工绩效-项目管理-成员列表导出

func (srv *StaffAssessServeice) ExportUserAssess(param *query.ExportAssessContentCycleDay) (*excelize.File, error) {
	transactionContext, err := factory.CreateTransactionContext(nil)
	if err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	if err := transactionContext.StartTransaction(); err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	defer func() {
		_ = transactionContext.RollbackTransaction()
	}()

	hrbp, err := srv.getHRBP(transactionContext, param.CompanyId, param.OperaterId)
	if err != nil {
		return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
	}

	assessDao := dao.NewStaffAssessDao(map[string]interface{}{
		"transactionContext": transactionContext,
	})
	contentList, err := assessDao.ExportDataUserAssess(dao.SearchConditin1{
		CompanyId:      param.CompanyId,
		CycleId:        param.CycleId,
		BeginDay:       "",
		TargetUserName: param.TargetUserName,
		TargetUserId:   param.TargetUserId,
		Limit:          5000,
		Offset:         0,
		OperaterId:     param.OperaterId,
		Hrbp:           hrbp,
	})
	if err != nil {
		return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, "获取数据列表"+err.Error())
	}

	if err := transactionContext.CommitTransaction(); err != nil {
		return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
	}
	//选择导出的评估项
	includeCol := map[string]struct{}{}
	for _, v := range param.ExportItems {
		includeCol[v.Category+"+"+v.Name] = struct{}{}
	}
	includeBeginDay := map[string]struct{}{}
	for _, v := range param.BeginDayList {
		includeBeginDay[v] = struct{}{}
	}

	eData := newExportData2()
	eData.setData(contentList)
	//将数据写入xlsx
	xlsxFile := excelize.NewFile()
	sheetIndex := xlsxFile.GetActiveSheetIndex()
	sheetName := xlsxFile.GetSheetName(sheetIndex)
	//写入第一行
	xlsxFile.SetCellStr(sheetName, "A1", "每日绩效汇总")
	xlsxFile.SetCellStr(sheetName, "A2", "日期")
	xlsxFile.MergeCell(sheetName, "A2", "A4")
	xlsxFile.SetCellStr(sheetName, "B2", "姓名")
	xlsxFile.MergeCell(sheetName, "B2", "B4")
	xlsxFile.SetCellStr(sheetName, "A5", "评估标准")
	//行数量
	rowNum := 0
	for _, v := range eData.rowSort.Child {
		//纵向-索引-第一列-日期
		if len(includeBeginDay) > 0 {
			if _, ok := includeBeginDay[v.Name]; !ok {
				continue
			}
		}
		for _, v2 := range v.Child {
			//纵向-索引-第二列-员工id
			//填充1,2 列
			rowNum++
			axisNum := fmt.Sprintf("%d", (rowNum-1)*3+6)
			userName := eData.userIdMap[v2.Name]
			xlsxFile.SetCellStr(sheetName, "A"+axisNum, v.Name)
			xlsxFile.SetCellStr(sheetName, "B"+axisNum, userName)
			axisEnd := fmt.Sprintf("%d", (rowNum-1)*3+6+2)
			xlsxFile.MergeCell(sheetName, "A"+axisNum, "A"+axisEnd)
			xlsxFile.MergeCell(sheetName, "B"+axisNum, "B"+axisEnd)
		}
	}
	//列数量
	colNum := 0
	for _, v := range eData.tableHeader.Child {
		//横向-评估指标-分类
		for _, v2 := range v.Child {
			//横向-评估指标-加分项、得分项
			for _, v3 := range v2.Child {
				// 横向-评估指标-名称
				//检查是否在指定的导出选项中
				if len(includeCol) > 0 {
					if _, ok := includeCol[v.Name+"+"+v3.Name]; !ok {
						continue
					}
				}
				colNum++
				//第几列
				colName, _ := excelize.ColumnNumberToName(colNum + 2)
				//填充 分类
				xlsxFile.SetCellStr(sheetName, colName+"2", v.Name)
				// 填充 加分项、得分项
				xlsxFile.SetCellStr(sheetName, colName+"3", v2.Name)
				// 填充 名称
				xlsxFile.SetCellStr(sheetName, colName+"4", v3.Name)
				if len(v3.Child) > 0 {
					//填充, 评估标准
					xlsxFile.SetCellStr(sheetName, colName+"5", v3.Child[0].Name)
				}
				xlsxFile.SetColWidth(sheetName, colName, colName, 30)
				rowNum = 0
				for _, v4 := range eData.rowSort.Child {
					//纵向-索引-第一列-日期
					if len(includeBeginDay) > 0 {
						if _, ok := includeBeginDay[v4.Name]; !ok {
							continue
						}
					}
					for _, v5 := range v4.Child {
						//纵向-索引-第二列-员工id
						rowNum++
						axis := fmt.Sprintf("%s%d", colName, (rowNum-1)*3+6)
						key := eData.dataKey(v5.Name, v4.Name, v.Name, v3.Name)
						if d, ok := eData.data[key]; ok {
							xlsxFile.SetCellStr(sheetName, axis, d.String())
						}
						axisEnd := fmt.Sprintf("%s%d", colName, (rowNum-1)*3+6+2)
						xlsxFile.MergeCell(sheetName, axis, axisEnd)
					}
				}
			}
		}
	}
	colName, _ := excelize.ColumnNumberToName(colNum + 2)
	xlsxFile.MergeCell(sheetName, "A1", colName+"1")
	return xlsxFile, nil
}