package excel

import (
	"encoding/json"
	"errors"
	"eta/eta_api/models/data_manage/excel"
	"eta/eta_api/services/data"
	excelServices "eta/eta_api/services/excel"
	"eta/eta_api/utils"
	"fmt"
	"github.com/araddon/dateparse"
	"github.com/shopspring/decimal"
	"github.com/xuri/excelize/v2"
	"strings"
)

// GetCustomAnalysisExcelData 获取自定义分析的表格data数据
func GetCustomAnalysisExcelData(excelInfo *excel.ExcelInfo) (luckySheet excelServices.LuckySheet, err error, errMsg string) {
	// 查找当前excel的sheet列表
	sheetList, err := excel.GetAllSheetList(excelInfo.ExcelInfoId)
	if err != nil {
		errMsg = "保存失败"
		err = errors.New("查找当前excel的sheet列表失败,Err:" + err.Error())
		return
	}
	currSheetMap := make(map[string]string)
	for _, sheet := range sheetList {
		currSheetMap[sheet.SheetName] = sheet.SheetName
	}

	sheetCellDataMapList := make(map[int][]excelServices.LuckySheetCellData)

	// 通过excel的id获取各个sheet的单元格数据map
	{
		dataList, tmpErr := excel.GetAllSheetDataListByExcelInfoId(excelInfo.ExcelInfoId)
		if tmpErr != nil {
			err = tmpErr
			return
		}

		for _, cellData := range dataList {
			sheetDataList, ok := sheetCellDataMapList[cellData.ExcelSheetId]
			if !ok {
				sheetDataList = make([]excelServices.LuckySheetCellData, 0)
			}

			tmpSheetDataList := make([]excelServices.LuckySheetCellData, 0)
			err = json.Unmarshal([]byte(cellData.Data), &tmpSheetDataList)
			if err != nil {
				return
			}
			sheetCellDataMapList[cellData.ExcelSheetId] = append(sheetDataList, tmpSheetDataList...)
		}
	}

	// 转成luckySheet的数据格式
	luckySheet = excelServices.LuckySheet{
		SheetList: make([]excelServices.LuckySheetData, 0),
	}

	for _, sheet := range sheetList {
		var luckySheetDataConfig excelServices.LuckySheetDataConfig
		err = json.Unmarshal([]byte(sheet.Config), &luckySheetDataConfig)
		if err != nil {
			return
		}
		tmpLuckySheetDataInfo := excelServices.LuckySheetData{
			Name:     sheet.SheetName,
			Index:    sheet.Sort,
			CellData: sheetCellDataMapList[sheet.ExcelSheetId],
			Config:   luckySheetDataConfig,
		}
		luckySheet.SheetList = append(luckySheet.SheetList, tmpLuckySheetDataInfo)
	}

	return
}

// GenerateExcelCustomAnalysisExcel 根据自定义分析的表格data数据生成excel
func GenerateExcelCustomAnalysisExcel(excelInfo *excel.ExcelInfo) (downloadFilePath string, err error, errMsg string) {
	luckySheet, err, errMsg := GetCustomAnalysisExcelData(excelInfo)
	if err != nil {
		return
	}

	downloadFilePath, err = luckySheet.ToExcel(false)

	return
}

// HandleEdbSequenceVal 处理日期集和数据集(获取可用的日期、数据集)
func HandleEdbSequenceVal(dateSequenceVal, dataSequenceVal []string) (newDateList []string, newDataList []float64, err error, errMsg string) {
	newDateList = make([]string, 0)
	newDataList = make([]float64, 0)

	// 数据集
	type dataStruct struct {
		Value float64
		Ok    bool
	}
	dataList := make([]dataStruct, 0)
	{
		for _, v := range dataSequenceVal {
			// 如果没有数据集,那么就过滤
			if v == `` {
				// 如果开始插入数据了,那么就需要插入不存在值
				dataList = append(dataList, dataStruct{
					Value: 0,
					Ok:    false,
				})
				continue
			}

			v = strings.Replace(v, ",", "", -1)
			v = strings.Replace(v, ",", "", -1)
			// 过滤空格
			v = strings.Replace(v, " ", "", -1)

			var tmpVal float64
			if strings.Contains(v, "%") {
				// 百分比的数
				isPercentage, percentageValue := utils.IsPercentage(v)
				if !isPercentage {
					dataList = append(dataList, dataStruct{
						Value: 0,
						Ok:    false,
					})
					continue
				}
				tmpValDec, tmpErr := decimal.NewFromString(percentageValue)
				if tmpErr != nil {
					dataList = append(dataList, dataStruct{
						Value: 0,
						Ok:    false,
					})
					continue
				}
				tmpVal, _ = tmpValDec.Div(decimal.NewFromFloat(100)).Float64()
			} else {
				tmpValDec, tmpErr := decimal.NewFromString(v)
				if tmpErr != nil {
					dataList = append(dataList, dataStruct{
						Value: 0,
						Ok:    false,
					})
					continue
				}
				tmpVal, _ = tmpValDec.Float64()
			}
			dataList = append(dataList, dataStruct{
				Value: tmpVal,
				Ok:    true,
			})
		}
	}

	// 日期集
	dateList := make([]string, 0)
	{
		for _, v := range dateSequenceVal {
			// 如果没有数据集,那么就过滤
			if v == `` {
				// 如果开始插入数据了,那么就需要插入不存在值
				dateList = append(dateList, "")
				continue
			}

			// 过滤空格
			v = strings.Replace(v, " ", "", -1)
			t1, tmpErr := dateparse.ParseAny(v)
			if tmpErr != nil {
				dateList = append(dateList, "")
				continue
			}

			dateList = append(dateList, t1.Format(utils.FormatDate))
		}
	}

	lenData := len(dataList)
	lenDate := len(dateList)

	// 最小个数
	num := lenDate
	if num > lenData {
		num = lenData
	}

	for i := 0; i < num; i++ {
		date := dateList[i]
		tmpData := dataList[i]

		// 日期为空、数据为空
		if !tmpData.Ok || date == `` {
			continue
		}

		newDateList = append(newDateList, date)
		newDataList = append(newDataList, tmpData.Value)
	}

	return
}

// Refresh  刷新表格关联的指标信息
func Refresh(excelInfo *excel.ExcelInfo) (err error, errMsg string, isSendEmail bool) {
	isSendEmail = true

	list, err := excel.GetAllExcelEdbMappingItemByExcelInfoId(excelInfo.ExcelInfoId)
	if err != nil {
		errMsg = "获取失败"
		return
	}

	// 没有关联指标,那么就退出吧
	if len(list) <= 0 {
		return
	}

	for k, v := range list {
		var tmpCalculateFormula excel.CalculateFormula
		err = json.Unmarshal([]byte(v.CalculateFormula), &tmpCalculateFormula)
		if err != nil {
			errMsg = "获取失败"
			err = errors.New("公式转换失败,Err:" + err.Error())
			return
		}
		v.DateSequenceStr = tmpCalculateFormula.DateSequenceStr
		v.DataSequenceStr = tmpCalculateFormula.DataSequenceStr
		list[k] = v
	}

	luckySheet, err, errMsg := GetCustomAnalysisExcelData(excelInfo)
	if err != nil {
		return
	}

	// 获取excel表格数据
	xlsxFile, err := luckySheet.GetExcelData(false)
	if err != nil {
		return
	}

	//fmt.Println(xlsxFile)

	// ResetCustomAnalysisData 数据重置的结构体
	type ResetCustomAnalysisData struct {
		EdbInfoId int
		DateList  []string
		DataList  []float64
	}

	for _, v := range list {
		dateList := make([]string, 0)
		dataList := make([]string, 0)

		// 日期序列
		{
			sheetName, startColumnName, endColumnName, startNum, endNum, isAll, isRow, isColumn, tmpErr := GetSheetStr(v.DateSequenceStr)
			if tmpErr != nil {
				err = tmpErr
				return
			}

			// 查找sheet页
			sheetInfo, ok := xlsxFile.Sheet[sheetName]
			if !ok {
				errMsg = "找不到" + sheetName
				err = errors.New(errMsg)
				return
			}

			startNum = startNum - 1
			endNum = endNum - 1
			// 选择行的数据
			if isRow {
				// 因为是选择一行的数据,所以开始行和结束行时一样的
				//endNum = startNum - 1

				// 开始列名、结束列
				var startColumn, endColumn int
				if isAll {
					// 结束列(其实也就是整列的个数)
					endColumn = len(sheetInfo.Cols) - 1
				} else {
					tmpStartColumn, tmpErr := excelize.ColumnNameToNumber(startColumnName)
					if tmpErr != nil {
						errMsg = "列名异常:" + startColumnName
						err = errors.New(errMsg)
						return
					}

					tmpEndColumn, tmpErr := excelize.ColumnNameToNumber(endColumnName)
					if tmpErr != nil {
						errMsg = "列名异常:" + endColumnName
						err = errors.New(errMsg)
						return
					}
					startColumn = tmpStartColumn - 1
					endColumn = tmpEndColumn - 1
				}

				for currColumn := startColumn; currColumn <= endColumn; currColumn++ {
					currCell := sheetInfo.Cell(startNum, currColumn)
					if currCell == nil {
						errMsg = fmt.Sprintf("第%d列,第%d行数据异常", startColumn, startNum)
						err = errors.New(errMsg)
						return
					}
					dateList = append(dateList, currCell.Value)
				}

			} else if isColumn { // 选择列的数据
				if isAll {
					// 选择一整列的话,结束行得根据实际情况调整(其实也就是整个sheet有多少行)
					endNum = len(sheetInfo.Rows) - 1
				}

				startColumn, tmpErr := excelize.ColumnNameToNumber(startColumnName)
				if tmpErr != nil {
					errMsg = "列名异常:" + startColumnName
					err = errors.New(errMsg)
					return
				}
				startColumn = startColumn - 1

				for currRow := startNum; currRow <= endNum; currRow++ {
					currCell := sheetInfo.Cell(currRow, startColumn)
					if currCell == nil {
						errMsg = fmt.Sprintf("第%d列,第%d行数据异常", startColumn, startNum)
						err = errors.New(errMsg)
						return
					}
					dateList = append(dateList, currCell.Value)
				}
			}

		}

		// 数据序列
		{
			sheetName, startColumnName, endColumnName, startNum, endNum, isAll, isRow, isColumn, tmpErr := GetSheetStr(v.DataSequenceStr)
			if tmpErr != nil {
				err = tmpErr
				return
			}

			// 查找sheet页
			sheetInfo, ok := xlsxFile.Sheet[sheetName]
			if !ok {
				errMsg = "找不到" + sheetName
				err = errors.New(errMsg)
				return
			}

			startNum = startNum - 1
			endNum = endNum - 1
			// 选择行的数据
			if isRow {
				// 开始列名、结束列
				var startColumn, endColumn int
				if isAll {
					// 结束列(其实也就是整列的个数)
					endColumn = len(sheetInfo.Cols) - 1
				} else {

					tmpStartColumn, tmpErr := excelize.ColumnNameToNumber(startColumnName)
					if tmpErr != nil {
						errMsg = "列名异常:" + startColumnName
						err = errors.New(errMsg)
						return
					}

					tmpEndColumn, tmpErr := excelize.ColumnNameToNumber(endColumnName)
					if tmpErr != nil {
						errMsg = "列名异常:" + endColumnName
						err = errors.New(errMsg)
						return
					}
					startColumn = tmpStartColumn - 1
					endColumn = tmpEndColumn - 1
				}

				for currColumn := startColumn; currColumn <= endColumn; currColumn++ {
					currCell := sheetInfo.Cell(startNum, currColumn)
					if currCell == nil {
						errMsg = fmt.Sprintf("第%d列,第%d行数据异常", startColumn, startNum)
						err = errors.New(errMsg)
						return
					}
					dataList = append(dataList, currCell.Value)
				}

			} else if isColumn { // 选择列的数据
				if isAll {
					// 选择一整列的话,结束行得根据实际情况调整(其实也就是整个sheet有多少行)
					endNum = len(sheetInfo.Rows) - 1
				}

				startColumn, tmpErr := excelize.ColumnNameToNumber(startColumnName)
				if tmpErr != nil {
					errMsg = "列名异常:" + startColumnName
					err = errors.New(errMsg)
					return
				}
				startColumn = startColumn - 1

				for currRow := startNum; currRow <= endNum; currRow++ {
					currCell := sheetInfo.Cell(currRow, startColumn)
					if currCell == nil {
						errMsg = fmt.Sprintf("第%d列,第%d行数据异常", startColumn, startNum)
						err = errors.New(errMsg)
						return
					}
					dataList = append(dataList, currCell.Value)
				}
			}

		}

		//fmt.Println("日期序列结束")

		// 将excel中的日期、数据系列处理
		relDateList, relDataList, tmpErr, tmpErrMsg := HandleEdbSequenceVal(dateList, dataList)
		if tmpErr != nil {
			err = tmpErr
			errMsg = tmpErrMsg
			return
		}
		req2 := &ResetCustomAnalysisData{
			EdbInfoId: v.EdbInfoId,
			DateList:  relDateList,
			DataList:  relDataList,
		}

		// 调用指标库去更新
		reqJson, tmpErr := json.Marshal(req2)
		if tmpErr != nil {
			err = tmpErr
			return
		}
		respItem, tmpErr := data.ResetCustomAnalysisData(string(reqJson))
		if tmpErr != nil {
			err = tmpErr
			return
		}
		if respItem.Ret != 200 {
			errMsg = respItem.Msg
			err = errors.New(respItem.ErrMsg)
			return
		}
		//sheetInfo.Cell()
	}

	//xlsxFile.Sheet[]

	return
}

// GetSheetStr
// @return sheetName string 用户选择的sheet名称
// @return startColumnName string 用户选择的开始列名称
// @return endColumnName string 用户选择的结束列名称
// @return startNum int 用户选择的开始列单元格位置
// @return endNum int 用户选择的结束列单元格位置
// @return isAll bool 是否选择整行/列数据
// @return isRow bool 是否选择行数据
// @return isColumn bool 是否选择列数据
func GetSheetStr(sequenceStr string) (sheetName, startColumnName, endColumnName string, startNum, endNum int, isAll, isRow, isColumn bool, err error) {
	// 找出sheetName
	tmpList := strings.Split(sequenceStr, "!")
	if len(tmpList) != 2 {
		err = errors.New("错误的公式,查找sheet异常:" + sequenceStr)
		return
	}

	sheetName = tmpList[0]

	// 分离开始/结束单元格
	tmpList = strings.Split(tmpList[1], ":")
	if len(tmpList) != 2 {
		err = errors.New("错误的公式,查找开始/结束单元格异常:" + sequenceStr)
		return
	}

	startList := strings.Split(tmpList[0], "$")
	endList := strings.Split(tmpList[1], "$")

	lenList := len(startList)
	if lenList != len(endList) {
		err = errors.New("错误的公式,开始与结束单元格异常:" + sequenceStr)
		return
	}

	if lenList != 3 && lenList != 2 {
		err = errors.New("错误的公式:" + sequenceStr)
		return
	}

	startColumnName = startList[1]
	endColumnName = endList[1]

	// 长度为2的话,那说明是整行或整列
	if lenList == 2 {
		isAll = true

		startDeci, tmpErr1 := decimal.NewFromString(startList[1])
		endDeci, tmpErr2 := decimal.NewFromString(endList[1])

		if tmpErr1 == nil && tmpErr2 == nil {
			isRow = true // 正常转换的话,那么就是整行
			startNum = int(startDeci.IntPart())
			endNum = int(endDeci.IntPart())
			startColumnName = ``
			endColumnName = ``

			return
		}

		if tmpErr1 == nil || tmpErr2 == nil {
			err = errors.New("错误的公式2:" + sequenceStr)
			return
		}

		// 如果不能转成数字,那么就是整列
		isColumn = true

		return
	}

	// 确定行
	startDeci, tmpErr1 := decimal.NewFromString(startList[2])
	endDeci, tmpErr2 := decimal.NewFromString(endList[2])
	if tmpErr1 != nil && tmpErr1 != tmpErr2 {
		err = errors.New("错误的公式3:" + sequenceStr)
		return
	}

	startNum = int(startDeci.IntPart())
	endNum = int(endDeci.IntPart())

	if startColumnName != endColumnName && startNum != endNum {
		err = errors.New("选区不允许跨行或者跨列")
	}

	if startColumnName == endColumnName {
		isColumn = true // 列数据
	} else {
		isRow = true // 行数据
	}

	return
}