package crontab

import (
	"fmt"
	"kpt-pasture/model"
	"sort"
	"time"

	"gitee.com/xuyiping_admin/pkg/logger/zaplog"
	"go.uber.org/zap"
)

func (e *Entry) UpdatePenBehavior() error {
	pastureList := e.FindPastureList()
	if pastureList == nil || len(pastureList) == 0 {
		return nil
	}

	for _, pasture := range pastureList {
		conf, err := e.GetSystemNeckRingConfigure(pasture.Id, model.MaxPenBehavior)
		if err != nil {
			zaplog.Error("UpdatePenBehavior", zap.Any("pasture", pasture), zap.Any("err", err))
			continue
		}
		e.PenBehavior(pasture.Id, conf.Value)
	}
	return nil
}

// PenBehavior 栏舍行为曲线
func (e *Entry) PenBehavior(pastureId, maxPenBehavior int64) {
	// 1. 获取颈环原始数据
	neckRingOriginalList, err := e.getNeckRingOriginalList(pastureId, maxPenBehavior)
	if err != nil {
		zaplog.Error("PenBehavior", zap.Any("pastureId", pastureId), zap.Any("maxPenBehavior", maxPenBehavior), zap.Any("err", err))
		return
	}

	if len(neckRingOriginalList) <= 0 {
		return
	}

	// 2. 获取牛只信息
	cowMap, err := e.getCowMap(pastureId, neckRingOriginalList)
	if err != nil {
		zaplog.Error("PenBehavior", zap.Any("pastureId", pastureId), zap.Any("neckRingOriginalList", neckRingOriginalList), zap.Any("err", err))
		return
	}

	// 3. 处理栏舍行为数据
	penData := e.processPenBehaviorData(neckRingOriginalList, cowMap)

	// 4. 计算平均值和百分比
	e.calculateAveragesAndRates(penData)

	// 5. 保存数据
	if err = e.savePenBehaviorData(penData); err != nil {
		zaplog.Error("PenBehavior", zap.Any("penData", penData), zap.Any("err", err))
		return
	}

	sort.Slice(neckRingOriginalList, func(i, j int) bool {
		return neckRingOriginalList[i].Id > neckRingOriginalList[j].Id
	})

	if err = e.UpdateSystemNeckRingConfigure(pastureId, model.MaxPenBehavior, neckRingOriginalList[0].Id); err != nil {
		zaplog.Error("PenBehavior", zap.Any("UpdateSystemNeckRingConfigure", err), zap.Any("neckRingOriginalList", neckRingOriginalList))
	}
}

// getNeckRingOriginalList 获取颈环原始数据
func (e *Entry) getNeckRingOriginalList(pastureId, maxPenBehavior int64) ([]*model.NeckRingOriginal, error) {
	var neckRingOriginalList []*model.NeckRingOriginal
	if err := e.DB.Model(new(model.NeckRingOriginal)).
		Where("id > ? AND pasture_id = ?", maxPenBehavior, pastureId).
		Order("active_date,neck_ring_number,frameid").
		Limit(int(defaultLimit)).
		Find(&neckRingOriginalList).Error; err != nil {
		return nil, err
	}
	return neckRingOriginalList, nil
}

// getCowMap 获取牛只信息映射
func (e *Entry) getCowMap(pastureId int64, neckRingOriginalList []*model.NeckRingOriginal) (map[string]*model.Cow, error) {
	// 提取牛只ID
	neckRingNumberList := make([]string, 0, len(neckRingOriginalList))
	for _, v := range neckRingOriginalList {
		neckRingNumberList = append(neckRingNumberList, v.NeckRingNumber)
	}

	// 获取牛只信息
	cowInfoList, err := e.GetCowByNeckRingNumbers(pastureId, neckRingNumberList)
	if err != nil {
		return nil, err
	}

	// 构建牛只信息映射
	cowMap := make(map[string]*model.Cow, len(cowInfoList))
	for _, v := range cowInfoList {
		if v.NeckRingNumber == "" {
			continue
		}
		cowMap[v.NeckRingNumber] = v
	}

	return cowMap, nil
}

// processPenBehaviorData 处理栏舍行为数据
func (e *Entry) processPenBehaviorData(neckRingOriginalList []*model.NeckRingOriginal, cowMap map[string]*model.Cow) map[string]*model.PenBehaviorData {
	penData := make(map[string]*model.PenBehaviorData, len(neckRingOriginalList))
	for _, v := range neckRingOriginalList {
		cowInfo, ok := cowMap[v.NeckRingNumber]
		if !ok {
			zaplog.Error("PenBehavior", zap.Any("neckRingNumber", v.NeckRingNumber))
			continue
		}

		key := fmt.Sprintf("%s_%d_%d", v.ActiveDate, cowInfo.PenId, v.Frameid)
		if data, exists := penData[key]; exists {
			data.CowCount++
			data.AvgHigh += v.High
			data.SumRumina += ifThenElse(v.Rumina >= 8, 1, 0)
			data.SumIntake += ifThenElse(v.Intake >= 8, 1, 0)
			data.SumRest += ifThenElse(v.Inactive >= 8, 1, 0)
			data.SumGasp += ifThenElse(v.Gasp >= 8, 1, 0)
		} else {
			penData[key] = &model.PenBehaviorData{
				PastureId: cowInfo.PastureId,
				PenId:     cowInfo.PenId,
				PenName:   cowInfo.PenName,
				HeatDate:  v.ActiveDate,
				Frameid:   v.Frameid,
				CowCount:  1,
				AvgHigh:   v.High,
			}
		}
	}
	return penData
}

// calculateAveragesAndRates 计算平均值和百分比
func (e *Entry) calculateAveragesAndRates(penData map[string]*model.PenBehaviorData) {
	for _, data := range penData {
		// 计算平均值
		data.AvgHigh = data.AvgHigh / data.CowCount

		// 计算百分比
		if data.CowCount > 0 {
			data.RuminaRate = int32(float64(data.SumRumina) / float64(data.CowCount) * 100)
			data.IntakeRate = int32(float64(data.SumIntake) / float64(data.CowCount) * 100)
			data.RestRate = int32(float64(data.SumRest) / float64(data.CowCount) * 100)
			data.GaspRate = int32(float64(data.SumGasp) / float64(data.CowCount) * 100)
		}
	}
}

// savePenBehaviorData 保存栏舍行为数据
func (e *Entry) savePenBehaviorData(penData map[string]*model.PenBehaviorData) error {
	for _, data := range penData {
		// 构建活动时间
		activeTime := e.calculateActiveTime(data.HeatDate, data.Frameid)

		// 构建保存数据
		penBehavior := model.NewPenBehavior(data, activeTime)

		// 使用 Upsert 操作
		if err := e.DB.Model(new(model.PenBehavior)).
			Where("pasture_id = ? AND heat_date = ? AND pen_id = ? AND active_time = ?",
				penBehavior.PastureId, penBehavior.HeatDate, penBehavior.PenId, penBehavior.ActiveTime).
			Assign(map[string]interface{}{
				"frameid":     penBehavior.Frameid,
				"cow_count":   penBehavior.CowCount,
				"avg_high":    penBehavior.AvgHigh,
				"sum_rumina":  penBehavior.SumRumina,
				"sum_intake":  penBehavior.SumIntake,
				"sum_rest":    penBehavior.SumRest,
				"sum_gasp":    penBehavior.SumGasp,
				"rumina_rate": penBehavior.RuminaRate,
				"intake_rate": penBehavior.IntakeRate,
				"rest_rate":   penBehavior.RestRate,
				"gasp_rate":   penBehavior.GaspRate,
			}).
			FirstOrCreate(penBehavior).Error; err != nil {
			return err
		}
	}
	return nil
}

// calculateActiveTime 计算活动时间
func (e *Entry) calculateActiveTime(heatDate string, frameid int32) string {
	// 计算小时和分钟
	hour := (frameid / 10) * 2
	minute := (frameid%10)*20 - 1
	if minute < 0 {
		minute = 0
	}

	baseDate, err := time.Parse(model.LayoutDate2, heatDate)
	if err != nil {
		zaplog.Error("PenBehavior", zap.Any("calculateActiveTime", err))
		return ""
	}
	baseTime := time.Date(baseDate.Year(), baseDate.Month(), baseDate.Day(), int(hour), 0, 0, 0, baseDate.Location())
	finalTime := baseTime.Add(time.Duration(minute) * time.Minute)
	// 构建时间字符串
	return finalTime.Format(model.LayoutTime)
}

// ifThenElse 条件判断函数
func ifThenElse(condition bool, a, b int32) int32 {
	if condition {
		return a
	}
	return b
}