package controllers

import (
	"encoding/json"
	"fmt"
	"math"
	"regexp"
	"strconv"
	"strings"
	"sws_xcx/enums"
	"sws_xcx/models"
	"sws_xcx/service"
	"sws_xcx/utils"
	"time"
	"unicode/utf8"
)

type CheckRecordApiController struct {
	BaseApiAuthController
}

// @Title GetCheckRecordList
// @Description 分页获取检测记录
// @Param   pageNum query int true "当前页(从1开始)"
// @Param   pageSize query int true "分页大小"
// @Success 200 {array} models.AppCheckRecordVO success
// @Failure 500 error
// @Security token
// @router /getcheckrecordlist [get]
func (c *CheckRecordApiController) GetCheckRecordList() {
	pageNum, _ := c.GetInt("pageNum", 1)
	pageSize, _ := c.GetInt("pageSize", 10)

	crs := service.NewCheckRecordService()
	rs, total, err := crs.GetCheckRecordList(pageNum, pageSize, c.CurrentUser.Id)
	if err != nil {
		c.ServeDynamicFailJsonSend(fmt.Sprintf("GetCheckRecordList err：%v", err))
		return
	}

	c.ServeSuccessPageJSON(rs, total)

}

// @Title GetCheckRecordItemReport
// @Description 获取检测报告
// @Param   itemnum query int true "项目编号"
// @Param   daymun query int true "最近几天"
// @Success 200 {array} models.AppCheckRecordItemReportVO success
// @Failure 500 error
// @Security token
// @router /getcheckrecorditemreport [get]
func (c *CheckRecordApiController) GetCheckRecordItemReport() {
	itemNum, err := c.GetInt("itemnum")
	if err != nil {
		c.ServeDynamicFailJsonSend(err.Error())
		return
	}
	dataNum, _ := c.GetInt("dataNum", 7)

	report, err := service.NewCheckRecordService().GetCheckRecordItemReport(dataNum, itemNum, c.CurrentUser.Id)
	if err != nil {
		c.ServeDynamicFailJsonSend(err.Error())
		return
	}

	c.ServeSuccessJSON(report)

}

// @Title GetCheckRecordItemById
// @Description 通过检测ID查看检测结果
// @Param   checkid query int true "检测ID"
// @Success 200 {object} models.AppCheckRecordItemVO success
// @Failure 500 error
// @Security token
// @router /getcheckrecorditembyid [get]
func (c *CheckRecordApiController) GetCheckRecordItemById() {

	id, err := c.GetInt64("checkid")
	if err != nil {
		c.ServeDynamicFailJsonSend(err.Error())
		return
	}
	crs := service.NewCheckRecordService()
	record, err := crs.GetCheckRecordById(id)
	if err != nil {
		c.ServeDynamicFailJsonSend(fmt.Sprintf("GetCheckRecord err：%v", err))
		return
	}
	recordItems, err := crs.GetCheckRecordItems(record.Id)
	if err != nil {
		c.ServeDynamicFailJsonSend(fmt.Sprintf("GetCheckRecordItems err：%v", err))
		return
	}
	checkItems, err := service.NewCheckItemService().GetCheckItems("cn", "1")

	if err != nil {
		c.ServeDynamicFailJsonSend(fmt.Sprintf("GetCheckItems err：%v", err))
		return
	}

	checkRecordItem, err := analyzeCheckRecord(recordItems, checkItems)
	if err != nil {
		c.ServeDynamicFailJsonSend(fmt.Sprintf("analyzeCheckRecord err：%v", err))
		return
	}
	checkRecordItem.CheckDate = models.Time(record.Ctime)
	checkRecordItem.UserID = int64(record.UserId)
	checkRecordItem.Bind = checkRecordItem.UserID > 0
	checkRecordItem.CheckRecordID = record.Id

	c.ServeSuccessJSON(checkRecordItem)
}

var DIGITS = []rune{
	'S', 'V', 'X', '5', '0', '8', '-', 'N',
	'i', 'm', 'd', 'u', 'H', 'O', 'Q', 'E',
	'D', 'v', 't', '2', 'c', 'p', '1', '3',
	'z', 'R', 'a', 'W', 'l', 'G', 'k', 'A',
	'9', 'o', 's', 'g', 'y', '4', 'w', 'L',
	'T', 'Y', 'b', '+', 'J', 'x', '7', 'r',
	'I', 'n', 'f', 'Z', 'e', 'M', 'C', 'P',
	'U', 'B', 'j', '6', 'F', 'K', 'h', 'q',
}

// @Title QrCodeCheckRecord
// @Description 通过扫描二维码查看检测结果
// @Param   qrcode query int true "扫描二维码的内容"
// @Success 200 {object} models.AppCheckRecordItemVO success
// @Failure 500 error
// @Security token
// @router /qrcodecheckrecord [get]
func (c *CheckRecordApiController) QrCodeCheckRecord() {
	result := c.GetString("qrcode")
	var userId uint64

	if result != "" {

		re := regexp.MustCompile(`(http.*/)?(.+)$`)
		matches := re.FindStringSubmatch(result)

		str := matches[2]

		parity := str[len(str)-1:]
		st := int8(0)
		result1 := result[:len(result)-1]

		for i := 0; i < utf8.RuneCountInString(result1); i++ {
			r, _ := utf8.DecodeRuneInString(result1[i:])
			st += int8(r)
			st = int8(getUint8(int(st)))
		}
		digit := DIGITS[getUint8(int(^st))%64]
		if string(digit) != parity {
			c.ServeDynamicFailJsonSend("检测数据校验不通过")
			return
		}
		item, err := strconv.ParseInt(str[:1], 16, 32)
		if err != nil {
			c.ServeDynamicFailJsonSend(fmt.Sprintf("无法解析检测结果: %v", err))
			return
		}
		if item != 14 && item != 11 {
			c.ServeDynamicFailJsonSend("无法解析检测结果")
			return
		}

		strs := str[1 : len(str)-1]
		strs = regexp.MustCompile(`[._&$|]`).ReplaceAllString(strs, " ")
		strsArray := strings.Fields(strs)

		if len(strsArray) < 5 {
			c.ServeDynamicFailJsonSend("无法解析检测结果")
			return
		}

		serialno := "09" + formatNumber(radixString(strsArray[0]), 8)
		serialno += formatNumber(radixString(strsArray[1]), 7)

		acc := int(radixString(strsArray[2]))

		checkResultStr := formatNumber(radixString(strsArray[3]), 7)
		if item == 14 {
			checkResultStr += formatNumber(radixString(strsArray[4]), 7)
		} else if item == 11 {
			checkResultStr += formatNumber(radixString(strsArray[4]), 4)
		}

		// fmt.Println("Device Name:", serialno)
		// fmt.Println("Acc:", acc)
		// fmt.Println("Check Result String:", checkResultStr)

		device, err := service.NewDeviceService().GetDeviceByNo(serialno)
		if err != nil {
			c.ServeDynamicFailJsonSend(fmt.Sprintf("GetDeviceByNo err：%v", err))
			return
		}
		if device.Id == 0 {
			c.ServeDynamicFailJsonSend("不是本系统中的设备，无法解析结果")
			return
		}
		ds := service.NewDeviceService()
		dr, err := ds.GetDeviceRelateByDeviceId(device.Id)
		if err != nil {
			c.ServeDynamicFailJsonSend(fmt.Sprintf("GetDeviceRelateByDeviceId err：%v", err))
			return
		}
		var status int
		if dr.Id == 0 {
			//设备未绑定 提示绑定
			status = 1

		} else if dr.UserId != userId {
			//别人已经绑定设备，返回结果 并提示
			status = 2

		} else {
			//自己绑定的设备，返回结果不提示
			status = 3
		}
		da := strings.Split(checkResultStr, "")
		count := len(da)
		checkItems, err := service.NewCheckItemService().GetCheckItems("cn", device.DeviceType)

		if err != nil {
			c.ServeDynamicFailJsonSend(fmt.Sprintf("GetCheckItems err：%v", err))
			return
		}
		crs := service.NewCheckRecordService()
		record, err := crs.GetCheckRecordByAcc(device.Id, acc)
		if err != nil {
			c.ServeDynamicFailJsonSend(fmt.Sprintf("GetCheckRecordByAcc err：%v", err))
			return
		}
		if record.Id == 0 {
			//创建记录
			err = ds.CreateDeviceMessageLog(models.DeviceMessageLog{
				DeviceName: device.DeviceName,
				Content:    result,
				EventType:  enums.EventTypeQrCode,
			})
			if err != nil {
				c.ServeDynamicFailJsonSend(fmt.Sprintf("CreateDeviceMessageLog err：%v", err))
				return
			}
			if len(checkItems) < count {
				c.ServeDynamicFailJsonSend("接收的数据与检查项目配置不一致")
				return
			}
			checkRecord := &models.CheckRecord{
				Acc:          acc,
				PutSources:   enums.EventTypeQrCode,
				DeviceId:     device.Id,
				UserId:       dr.UserId,
				DeviceStatus: device.Status,
				Ctime:        time.Now(),
			}
			if dr.UserId > 0 {

				hp, err := service.NewUserHealthProfileService().GetUserHealthProfileByUserId(dr.UserId)
				if err != nil {
					c.ServeDynamicFailJsonSend(fmt.Sprintf("GetUserHealthProfileByUserId err：%v", err))
					return
				}
				checkRecord.UserHealthProfileId = int64(hp.Id)
			}
			err = crs.CreateCheckRecord(checkRecord)
			if err != nil {
				c.ServeDynamicFailJsonSend(fmt.Sprintf("CreateCheckRecord err：%v", err))
				return
			}
			alerts := make([]string, 0)
			for i := 0; i < count; i++ {
				vi, _ := strconv.Atoi(da[i])
				err = createCheckRecordItem(checkItems, checkRecord.Id, &alerts, vi, i+1, crs)
				if err != nil {
					utils.ErrorLog("createCheckRecordItem valule:%v, err:%v:", vi, err)
				}
			}

			if len(alerts) > 0 {
				alertItemIds := strings.Join(alerts, ",")
				err = crs.UpdateCheckRecordAlertItems(checkRecord.Id, alertItemIds)
				if err != nil {
					c.ServeDynamicFailJsonSend(fmt.Sprintf("UpdateCheckRecordAlertItems err：%v", err))
					return
				}

			} else {
				utils.TraceLog("无异常数据")
			}
			record = *checkRecord
		}

		recordItems, err := crs.GetCheckRecordItems(record.Id)
		if err != nil {
			c.ServeDynamicFailJsonSend(fmt.Sprintf("GetCheckRecordItems err：%v", err))
			return
		}
		checkRecordItem, err := analyzeCheckRecord(recordItems, checkItems)
		if err != nil {
			c.ServeDynamicFailJsonSend(fmt.Sprintf("analyzeCheckRecord err：%v", err))
			return
		}
		checkRecordItem.Status = status
		checkRecordItem.CheckDate = models.Time(record.Ctime)
		checkRecordItem.UserID = int64(record.UserId)
		checkRecordItem.Bind = checkRecordItem.UserID > 0
		checkRecordItem.CheckRecordID = record.Id

		c.ServeSuccessJSON(checkRecordItem)

	}
}
func analyzeCheckRecord(ritems []*models.CheckRecordItem, citems []*models.CheckItem) (models.AppCheckRecordItemVO, error) {
	var result models.AppCheckRecordItemVO
	var details []models.AppCheckRecordItemDetailsVO

	for _, ri := range ritems {
		detail := models.AppCheckRecordItemDetailsVO{}
		item := findItem(citems, ri.CheckItemId)
		if item == nil {
			continue
		}
		if ri.CheckValue != "" && item.ScopeList != "" {
			var scopes []*models.CheckItemScopeVO
			err := json.Unmarshal([]byte(item.ScopeList), &scopes)
			if err != nil {
				return result, err
			}
			for _, scope := range scopes {
				if ri.CheckValueIndex == scope.Index {
					if scope.Type == 1 {
						result.NormalCount += 1
						detail.Alert = false

					} else {
						result.AlertCount += 1
						detail.Alert = true
					}
					detail.ValueIndex = strconv.Itoa(ri.CheckValueIndex)
					detail.ID = item.Id
					detail.Value = scope.Value
					detail.NameCn = item.NameCn
					detail.NameEn = item.NameEn
					detail.ReferenceValue = item.ReferenceValue
					//detail.Describe = item.Details
					detail.Unit = item.Unit
					details = append(details, detail)
					break
				}
			}
			result.Items = details
			if result.AlertCount > 1 {
				result.AlertGrade = enums.AlertGradeHIGH
			} else if result.AlertCount == 1 {
				result.AlertGrade = enums.AlertGradeMEDIUM

			} else {
				result.AlertGrade = enums.AlertGradeNORMAL
			}
			result.Describe = enums.AlertGradeMap[result.AlertGrade]
		}
	}

	return result, nil
}

func formatNumber(num int64, width int) string {
	format := fmt.Sprintf("%%0%dd", width)
	return fmt.Sprintf(format, num)
}

func getUint8(val int) uint8 {
	return uint8(val & 0xFF)
}

func indexDigits(ch rune) int {
	for i, digit := range DIGITS {
		if ch == digit {
			return i
		}
	}
	return -1
}

func radixString(str string) int64 {
	sum := int64(0)
	len := len(str)

	for i := 0; i < len; i++ {
		index := indexDigits(rune(str[len-i-1]))
		sum += int64(index) * int64(math.Pow(64, float64(i)))
	}

	return sum
}
