package backend

import (
	"context"
	"encoding/json"
	"fmt"
	"kpt-tmr-group/model"
	"kpt-tmr-group/pkg/logger/zaplog"
	"kpt-tmr-group/pkg/tool"
	"kpt-tmr-group/pkg/xerr"
	operationPb "kpt-tmr-group/proto/go/backend/operation"
	"net/http"
	"sort"
	"sync"
	"time"

	"go.uber.org/multierr"
	"go.uber.org/zap"
)

const compareTime = 10 * 60

// PasturePrefAnalysisData  PasturePrefExecTimeData PastureSprinkleFeedTime TODO  后期三个函数封装一下
func (s *StoreEntry) PasturePrefAnalysisData(ctx context.Context, req *operationPb.SearchAnalysisAccuracyRequest) (map[int64]*model.PastureAnalysisAccuracyData, error) {
	res := make(map[int64]*model.PastureAnalysisAccuracyData, 0)

	wg := sync.WaitGroup{}
	wg.Add(len(req.PastureIds))

	for _, pastureId := range req.PastureIds {
		go func(pId int32) {
			defer wg.Done()

			response := &model.PastureAnalysisAccuracyResponse{}
			groupPasture, err := s.GetGroupPastureListById(ctx, int64(pId))
			if err != nil {
				zaplog.Error("PasturePrefAnalysisData",
					zap.Any("GetGroupPastureListById", err),
					zap.Any("pId", pId))
				return
			}

			body := &model.DashboardAccuracyRequest{
				PastureId:              int32(groupPasture.PastureId),
				FeedFormulaId:          req.FeedFormulaId,
				CattleParentCategoryId: int32(req.CattleParentCategoryId),
				StartDate:              req.StartDate,
				EndDate:                req.EndDate,
			}
			_, err = s.PastureHttpClient(ctx, model.DashboardAccuracyUrl, int64(pId), body, response)
			if err != nil {
				zaplog.Error("DistributeFeedFormula",
					zap.String("url", model.DashboardAccuracyUrl),
					zap.Any("pasture", groupPasture), zap.Any("body", body),
					zap.Any("err", err), zap.Any("response", response))
				b, _ := json.Marshal(body)
				resB, _ := json.Marshal(response)
				pastureDataLog := model.NewPastureDataLog(groupPasture.Id, PastureDataLogType["FeedFormula_Distribute"], model.DashboardAccuracyUrl, string(b), string(resB))
				s.DB.Create(pastureDataLog)
				return
			}
			if response.Code != http.StatusOK {
				zaplog.Error("DistributeFeedFormula-response",
					zap.String("url", model.DashboardAccuracyUrl),
					zap.Any("pasture", groupPasture), zap.Any("body", body),
					zap.Any("response", response), zap.Any("response", response))
				return
			}
			res[groupPasture.Id] = response.Data

		}(pastureId)
	}
	wg.Wait()
	return res, nil
}

func (s *StoreEntry) PasturePrefExecTimeData(ctx context.Context, req *operationPb.SearchAnalysisAccuracyRequest) (map[string]*model.ExecTimeData, error) {

	res := make(map[string]*model.ExecTimeData, 0)
	wg := sync.WaitGroup{}
	wg.Add(len(req.PastureIds))

	for _, pastureId := range req.PastureIds {
		go func(pId int32) {
			defer wg.Done()

			groupPasture, err := s.GetGroupPastureListById(ctx, int64(pId))
			if err != nil {
				return
			}

			response := &model.PastureExecTimeData{}
			body := &model.DashboardAccuracyRequest{
				PastureId:              int32(groupPasture.PastureId),
				FeedFormulaId:          req.FeedFormulaId,
				CattleParentCategoryId: int32(req.CattleParentCategoryId),
				StartDate:              req.StartDate,
				EndDate:                req.EndDate,
			}
			if _, err = s.PastureHttpClient(ctx, model.DashboardExecTimeUrl, int64(pId), body, response); err != nil {
				zaplog.Error("PasturePrefExecTimeData",
					zap.String("url", model.DashboardExecTimeUrl),
					zap.Any("pasture", groupPasture), zap.Any("body", body),
					zap.Any("err", err), zap.Any("response", response))
				b, _ := json.Marshal(body)
				resB, _ := json.Marshal(response)
				pastureDataLog := model.NewPastureDataLog(groupPasture.Id, PastureDataLogType["PasturePrefExecTimeData"], model.DashboardExecTimeUrl, string(b), string(resB))
				s.DB.Create(pastureDataLog)
				return
			}
			if response.Code != http.StatusOK {
				zaplog.Error("PasturePrefExecTimeData-response",
					zap.String("url", model.DashboardExecTimeUrl),
					zap.Any("pasture", groupPasture), zap.Any("body", body),
					zap.Any("err", err), zap.Any("response", response))
				return
			}
			res[groupPasture.Name] = response.Data

		}(pastureId)
	}
	wg.Wait()
	return res, nil
}

func (s *StoreEntry) PastureSprinkleFeedTime(ctx context.Context, req *operationPb.SprinkleFeedTimeRequest) (map[string][]*model.SprinkleStatisticsDataList, error) {

	res := make(map[string][]*model.SprinkleStatisticsDataList, 0)
	wg := sync.WaitGroup{}
	wg.Add(len(req.PastureIds))
	var muError error
	for _, pasture := range req.PastureIds {
		go func(pId int32) {
			defer wg.Done()

			groupPasture, err := s.GetGroupPastureListById(ctx, int64(pId))
			if err != nil {
				zaplog.Error("PastureSprinkleFeedTime", zap.Any("GetGroupPastureListById", err))
				return
			}

			response := &model.PastureSprinkleStatisticsDataList{}
			body := &model.DashboardAccuracyRequest{
				PastureId:     int32(groupPasture.PastureId),
				FeedFormulaId: req.FeedFormulaId,
				StartDate:     req.StartDate,
				EndDate:       req.EndDate,
			}
			if _, err = s.PastureHttpClient(ctx, model.DashboardSprinkleFeedTimeUrl, int64(pId), body, response); err != nil {
				muError = multierr.Append(muError, err)
				zaplog.Error("PastureSprinkleFeedTime",
					zap.String("url", model.DashboardSprinkleFeedTimeUrl),
					zap.Any("pasture", groupPasture), zap.Any("body", body),
					zap.Any("err", err), zap.Any("response", response))
				b, _ := json.Marshal(body)
				resB, _ := json.Marshal(response)
				pastureDataLog := model.NewPastureDataLog(groupPasture.Id, PastureDataLogType["PasturePrefExecTimeData"], model.DashboardSprinkleFeedTimeUrl, string(b), string(resB))
				s.DB.Create(pastureDataLog)
			}
			if response.Code != http.StatusOK {
				muError = multierr.Append(muError, xerr.Custom(response.Msg))
			}
			res[groupPasture.Name] = response.Data
		}(pasture)
	}
	wg.Wait()
	return res, nil
}

func (s *StoreEntry) SearchAnalysisAccuracy(ctx context.Context, req *operationPb.SearchAnalysisAccuracyRequest) (*model.SearchAnalysisAccuracyResponse, error) {
	res := &model.SearchAnalysisAccuracyResponse{
		Code: http.StatusOK,
		Msg:  "ok",
		Data: &model.AnalysisAccuracyData{
			Chart: &model.Chart{},
			Table: &model.Table{
				TitleList: make([]*model.TableList, 0),
				DataList:  &model.DataList{},
			},
		},
	}
	res.Data.Table.TitleList = append(res.Data.Table.TitleList, &model.TableList{
		Name:  "title",
		Value: "牧场",
	})
	pastureAnalysisAccuracy, err := s.PasturePrefAnalysisData(ctx, req)
	if err != nil {
		return nil, xerr.WithStack(err)
	}

	mixedFodderAccurateRatio, mixedFodderCorrectRatio, sprinkleFodderAccurateRatio, sprinkleFodderCorrectRatio :=
		&model.CommonValueRatio{}, &model.CommonValueRatio{}, &model.CommonValueRatio{}, &model.CommonValueRatio{}
	maTitleValueList, mcTitleValueList, saTitleValueList, scTitleValueList := make([]float64, 0), make([]float64, 0), make([]float64, 0), make([]float64, 0)
	dayTimeList := tool.TimeBetween(req.StartDate, req.EndDate)
	for pastureId, data := range pastureAnalysisAccuracy {
		groupPasture, err := s.GetGroupPastureListById(ctx, pastureId)
		if err != nil {
			zaplog.Error("SearchAnalysisAccuracy GetGroupPastureListById",
				zap.Any("pastureId", pastureId), zap.Any("error", err))
			continue
		}
		if data == nil {
			continue
		}

		mixedFodderAccurateRatioDataList := make([]string, 0)
		for _, v := range data.MixedFodderAccurateRatio {
			mixedFodderAccurateRatioDataList = append(mixedFodderAccurateRatioDataList, fmt.Sprintf("%.2f", v.Ratio))
			if len(mixedFodderAccurateRatio.DateDay) < len(dayTimeList) {
				mixedFodderAccurateRatio.DateDay = append(mixedFodderAccurateRatio.DateDay, v.DayTime)
			}
			maTitleValueList = append(maTitleValueList, v.Ratio)
		}

		mixedFodderAccurateRatio.DataList = append(mixedFodderAccurateRatio.DataList, mixedFodderAccurateRatioDataList)
		mixedFodderAccurateRatio.PastureIds = append(mixedFodderAccurateRatio.PastureIds, int32(pastureId))
		mixedFodderAccurateRatio.PastureName = append(mixedFodderAccurateRatio.PastureName, groupPasture.Name)

		mixedFodderCorrectRatioDataList := make([]string, 0)
		for _, v := range data.MixedFodderCorrectRatio {
			mixedFodderCorrectRatioDataList = append(mixedFodderCorrectRatioDataList, fmt.Sprintf("%.2f", v.Ratio))
			if len(mixedFodderCorrectRatio.DateDay) < len(dayTimeList) {
				mixedFodderCorrectRatio.DateDay = append(mixedFodderCorrectRatio.DateDay, v.DayTime)
			}
			mcTitleValueList = append(mcTitleValueList, v.Ratio)
		}

		mixedFodderCorrectRatio.DataList = append(mixedFodderCorrectRatio.DataList, mixedFodderCorrectRatioDataList)
		mixedFodderCorrectRatio.PastureIds = append(mixedFodderCorrectRatio.PastureIds, int32(pastureId))
		mixedFodderCorrectRatio.PastureName = append(mixedFodderCorrectRatio.PastureName, groupPasture.Name)

		sprinkleFodderRatioDataList := make([]string, 0)
		for _, v := range data.SprinkleFodderAccurateRatio {
			sprinkleFodderRatioDataList = append(sprinkleFodderRatioDataList, fmt.Sprintf("%.2f", v.Ratio))
			if len(sprinkleFodderAccurateRatio.DateDay) < len(dayTimeList) {
				sprinkleFodderAccurateRatio.DateDay = append(sprinkleFodderAccurateRatio.DateDay, v.DayTime)
			}
			saTitleValueList = append(saTitleValueList, v.Ratio)
		}

		sprinkleFodderAccurateRatio.DataList = append(sprinkleFodderAccurateRatio.DataList, sprinkleFodderRatioDataList)
		sprinkleFodderAccurateRatio.PastureIds = append(sprinkleFodderAccurateRatio.PastureIds, int32(pastureId))
		sprinkleFodderAccurateRatio.PastureName = append(sprinkleFodderAccurateRatio.PastureName, groupPasture.Name)

		sprinkleFodderCorrectRatioDataList := make([]string, 0)
		for _, v := range data.SprinkleFodderCorrectRatio {
			sprinkleFodderCorrectRatioDataList = append(sprinkleFodderCorrectRatioDataList, fmt.Sprintf("%.2f", v.Ratio))
			if len(sprinkleFodderCorrectRatio.DateDay) < len(dayTimeList) {
				sprinkleFodderCorrectRatio.DateDay = append(sprinkleFodderCorrectRatio.DateDay, v.DayTime)
			}
			scTitleValueList = append(scTitleValueList, v.Ratio)
		}

		sprinkleFodderCorrectRatio.DataList = append(sprinkleFodderCorrectRatio.DataList, sprinkleFodderCorrectRatioDataList)
		sprinkleFodderCorrectRatio.PastureIds = append(sprinkleFodderCorrectRatio.PastureIds, int32(pastureId))
		sprinkleFodderCorrectRatio.PastureName = append(sprinkleFodderCorrectRatio.PastureName, groupPasture.Name)
	}

	pastureTopDataList, err := s.TopPasture(ctx, req)
	if err != nil {
		zaplog.Error("SearchAnalysisAccuracy", zap.Any("TopPasture", err), zap.Any("request", req))
		return nil, xerr.WithStack(err)
	}

	sort.Float64s(maTitleValueList)
	mixedFodderAccurateRatio.MaxValue = fmt.Sprintf("%.2f", maTitleValueList[len(maTitleValueList)-1])
	mixedFodderAccurateRatio.MinValue = fmt.Sprintf("%.2f", maTitleValueList[0])
	mixedFodderAccurateRatio.MiddleValue = fmt.Sprintf("%.2f", tool.Median(maTitleValueList))
	mixedFodderAccurateRatio.TopOneName = pastureTopDataList.Data.MixedFodderAccurateRatio[0].PastureName

	sort.Float64s(mcTitleValueList)
	mixedFodderCorrectRatio.MaxValue = fmt.Sprintf("%.2f", mcTitleValueList[len(mcTitleValueList)-1])
	mixedFodderCorrectRatio.MinValue = fmt.Sprintf("%.2f", mcTitleValueList[0])
	mixedFodderCorrectRatio.MiddleValue = fmt.Sprintf("%.2f", tool.Median(mcTitleValueList))
	mixedFodderCorrectRatio.TopOneName = pastureTopDataList.Data.MixedFodderCorrectRatio[0].PastureName

	sort.Float64s(saTitleValueList)
	sprinkleFodderAccurateRatio.MaxValue = fmt.Sprintf("%.2f", saTitleValueList[len(saTitleValueList)-1])
	sprinkleFodderAccurateRatio.MinValue = fmt.Sprintf("%.2f", saTitleValueList[0])
	sprinkleFodderAccurateRatio.MiddleValue = fmt.Sprintf("%.2f", tool.Median(saTitleValueList))
	sprinkleFodderAccurateRatio.TopOneName = pastureTopDataList.Data.SprinkleFodderAccurateRatio[0].PastureName

	sort.Float64s(scTitleValueList)
	sprinkleFodderCorrectRatio.MaxValue = fmt.Sprintf("%.2f", scTitleValueList[len(scTitleValueList)-1])
	sprinkleFodderCorrectRatio.MinValue = fmt.Sprintf("%.2f", scTitleValueList[0])
	sprinkleFodderCorrectRatio.MiddleValue = fmt.Sprintf("%.2f", tool.Median(scTitleValueList))
	sprinkleFodderCorrectRatio.TopOneName = pastureTopDataList.Data.SprinkleFodderCorrectRatio[0].PastureName

	chart := &model.Chart{
		MixedFodderAccurateRatio:    mixedFodderAccurateRatio,
		MixedFodderCorrectRatio:     mixedFodderCorrectRatio,
		SprinkleFodderAccurateRatio: sprinkleFodderAccurateRatio,
		SprinkleFodderCorrectRatio:  sprinkleFodderCorrectRatio,
	}

	res.Data.Chart = chart
	res.Data.Table = s.TitleList(ctx, pastureAnalysisAccuracy)
	return res, nil
}

// TopPasture 牧场排名
func (s *StoreEntry) TopPasture(ctx context.Context, req *operationPb.SearchAnalysisAccuracyRequest) (*model.GetPastureTopResponse, error) {
	dashboardTopData := &model.PastureTop{
		MixedFodderAccurateRatio:    make([]*model.PastureTopData, 0),
		MixedFodderCorrectRatio:     make([]*model.PastureTopData, 0),
		SprinkleFodderAccurateRatio: make([]*model.PastureTopData, 0),
		SprinkleFodderCorrectRatio:  make([]*model.PastureTopData, 0),
	}
	res := &model.GetPastureTopResponse{
		Code: http.StatusOK,
		Msg:  "ok",
		Data: nil,
	}
	analysisAccuracy, err := s.PasturePrefAnalysisData(ctx, req)
	if err != nil {
		return nil, xerr.WithStack(err)
	}

	for pastureId, data := range analysisAccuracy {
		groupPasture, err := s.GetGroupPastureListById(ctx, pastureId)
		if err != nil {
			zaplog.Error("TopPasture", zap.Any("GetGroupPastureListById", pastureId), zap.Any("err", err))
			continue
		}
		if data == nil {
			continue
		}

		allMaRatio, allMcRatio, allSaRatio, allScRatio := 0.0, 0.0, 0.0, 0.0
		for _, v := range data.MixedFodderAccurateRatio {
			allMaRatio += v.Ratio
		}
		dashboardTopData.MixedFodderAccurateRatio = append(dashboardTopData.MixedFodderAccurateRatio, &model.PastureTopData{
			PastureName: groupPasture.Name,
			Ratio:       tool.Decimal(allMaRatio / float64(len(data.MixedFodderAccurateRatio))),
		})

		for _, v := range data.MixedFodderCorrectRatio {
			allMcRatio += v.Ratio
		}
		dashboardTopData.MixedFodderCorrectRatio = append(dashboardTopData.MixedFodderCorrectRatio, &model.PastureTopData{
			PastureName: groupPasture.Name,
			Ratio:       tool.Decimal(allMaRatio / float64(len(data.MixedFodderCorrectRatio))),
		})

		for _, v := range data.SprinkleFodderAccurateRatio {
			allSaRatio += v.Ratio
		}
		dashboardTopData.SprinkleFodderAccurateRatio = append(dashboardTopData.SprinkleFodderAccurateRatio, &model.PastureTopData{
			PastureName: groupPasture.Name,
			Ratio:       tool.Decimal(allSaRatio / float64(len(data.SprinkleFodderAccurateRatio))),
		})

		for _, v := range data.SprinkleFodderCorrectRatio {
			allScRatio += v.Ratio
		}
		dashboardTopData.SprinkleFodderCorrectRatio = append(dashboardTopData.SprinkleFodderCorrectRatio, &model.PastureTopData{
			PastureName: groupPasture.Name,
			Ratio:       tool.Decimal(allScRatio / float64(len(data.SprinkleFodderCorrectRatio))),
		})
	}

	sort.Slice(dashboardTopData.MixedFodderAccurateRatio, func(i, j int) bool {
		return dashboardTopData.MixedFodderAccurateRatio[i].Ratio > dashboardTopData.MixedFodderAccurateRatio[j].Ratio
	})
	sort.Slice(dashboardTopData.MixedFodderCorrectRatio, func(i, j int) bool {
		return dashboardTopData.MixedFodderCorrectRatio[i].Ratio > dashboardTopData.MixedFodderCorrectRatio[j].Ratio
	})
	sort.Slice(dashboardTopData.SprinkleFodderAccurateRatio, func(i, j int) bool {
		return dashboardTopData.SprinkleFodderAccurateRatio[i].Ratio > dashboardTopData.SprinkleFodderAccurateRatio[j].Ratio
	})
	sort.Slice(dashboardTopData.SprinkleFodderCorrectRatio, func(i, j int) bool {
		return dashboardTopData.SprinkleFodderCorrectRatio[i].Ratio > dashboardTopData.SprinkleFodderCorrectRatio[j].Ratio
	})

	if req.DashboardTopType > 0 {
		switch req.DashboardTopType {
		case operationPb.DashboardTopType_MIXED_ACCURATE:
			dashboardTopData.MixedFodderAccurateRatio = dashboardTopRand(req, dashboardTopData.MixedFodderAccurateRatio)
		case operationPb.DashboardTopType_MIXED_CORRECT:
			dashboardTopData.MixedFodderCorrectRatio = dashboardTopRand(req, dashboardTopData.MixedFodderCorrectRatio)
		case operationPb.DashboardTopType_SPRINKLE_ACCURATE:
			dashboardTopData.SprinkleFodderAccurateRatio = dashboardTopRand(req, dashboardTopData.SprinkleFodderAccurateRatio)
		case operationPb.DashboardTopType_Sprinkle_CORRECT:
			dashboardTopData.SprinkleFodderCorrectRatio = dashboardTopRand(req, dashboardTopData.SprinkleFodderCorrectRatio)
		}
	}

	res.Data = dashboardTopData
	return res, nil
}

func (s *StoreEntry) TitleList(ctx context.Context, pastureAnalysisList map[int64]*model.PastureAnalysisAccuracyData) *model.Table {
	res := &model.Table{
		TitleList: make([]*model.TableList, 0),
		DataList: &model.DataList{
			MixedFodderAccurateRatio:    make([]map[string]string, 0),
			MixedFodderCorrectRatio:     make([]map[string]string, 0),
			SprinkleFodderAccurateRatio: make([]map[string]string, 0),
			SprinkleFodderCorrectRatio:  make([]map[string]string, 0),
		},
	}

	for pastureId, data := range pastureAnalysisList {
		groupPasture, err := s.GetGroupPastureListById(ctx, pastureId)
		if err != nil {
			zaplog.Info("TitleList", zap.Any("GetGroupPastureListById", pastureId), zap.Any("err", err))
			continue
		}

		if len(res.TitleList) <= len(data.MixedFodderAccurateRatio) {
			res.TitleList = append(res.TitleList, &model.TableList{
				Name:  "title",
				Value: "牧场",
			})
		}

		maMap := map[string]string{
			"title": groupPasture.Name,
		}
		for i, v := range data.MixedFodderCorrectRatio {
			maMap[fmt.Sprintf("data%d", i+1)] = fmt.Sprintf("%.2f", v.Ratio)
			if len(res.TitleList) <= len(data.MixedFodderAccurateRatio) {
				res.TitleList = append(res.TitleList, &model.TableList{
					Name:  fmt.Sprintf("data%d", i+1),
					Value: v.DayTime,
				})
			}
		}
		res.DataList.MixedFodderAccurateRatio = append(res.DataList.MixedFodderAccurateRatio, maMap)

		mcMap := map[string]string{
			"title": groupPasture.Name,
		}
		for i, v := range data.MixedFodderCorrectRatio {
			mcMap[fmt.Sprintf("data%d", i+1)] = fmt.Sprintf("%.2f", v.Ratio)
		}
		res.DataList.MixedFodderCorrectRatio = append(res.DataList.MixedFodderCorrectRatio, mcMap)

		saMap := map[string]string{
			"title": groupPasture.Name,
		}
		for i, v := range data.SprinkleFodderAccurateRatio {
			saMap[fmt.Sprintf("data%d", i+1)] = fmt.Sprintf("%.2f", v.Ratio)
		}
		res.DataList.SprinkleFodderAccurateRatio = append(res.DataList.SprinkleFodderAccurateRatio, saMap)

		scMap := map[string]string{
			"title": groupPasture.Name,
		}
		for i, v := range data.SprinkleFodderCorrectRatio {
			scMap[fmt.Sprintf("data%d", i+1)] = fmt.Sprintf("%.2f", v.Ratio)
		}
		res.DataList.SprinkleFodderCorrectRatio = append(res.DataList.SprinkleFodderCorrectRatio, scMap)
	}

	return res
}

func (s *StoreEntry) ExecutionTime(ctx context.Context, req *operationPb.SearchAnalysisAccuracyRequest) (*model.ExecTimeResponse, error) {
	res := &model.ExecTimeResponse{
		Code: http.StatusOK,
		Msg:  "ok",
		Data: &model.ExecTimeDataList{
			Chart: &model.ExecTimeDataListChart{
				Title:        make([]string, 0),
				AddFeedTime:  make([][]string, 0),
				SprinkleTime: make([][]string, 0),
				StirTime:     make([][]string, 0),
			},
			TableList: make([]map[string]string, 0),
		},
	}

	pastureExecTime, err := s.PasturePrefExecTimeData(ctx, req)
	if err != nil {
		return nil, xerr.WithStack(err)
	}

	for pastureName, execTime := range pastureExecTime {
		res.Data.Chart.Title = append(res.Data.Chart.Title, pastureName)
		addFeedTimeStr, sprinkleTimeStr, stirTimeStr := make([]string, 0), make([]string, 0), make([]string, 0)
		if execTime != nil {
			addFeedTimeStr = append(addFeedTimeStr, execTime.AddFeedTime.MaxValue, execTime.AddFeedTime.UpMiddleValue,
				execTime.AddFeedTime.MiddleValue, execTime.AddFeedTime.DownMiddleValue, execTime.AddFeedTime.MinValue)

			sprinkleTimeStr = append(sprinkleTimeStr, execTime.SprinkleTime.MaxValue, execTime.SprinkleTime.UpMiddleValue,
				execTime.SprinkleTime.MiddleValue, execTime.SprinkleTime.DownMiddleValue, execTime.SprinkleTime.MinValue)

			stirTimeStr = append(stirTimeStr, execTime.StirTime.MaxValue, execTime.StirTime.UpMiddleValue,
				execTime.StirTime.MiddleValue, execTime.StirTime.DownMiddleValue, execTime.StirTime.MinValue)
		}

		res.Data.Chart.AddFeedTime = append(res.Data.Chart.AddFeedTime, addFeedTimeStr)
		res.Data.Chart.SprinkleTime = append(res.Data.Chart.SprinkleTime, sprinkleTimeStr)
		res.Data.Chart.StirTime = append(res.Data.Chart.StirTime, stirTimeStr)
		if execTime == nil {
			continue
		}
		tableList := map[string]string{
			"title":                           pastureName,
			"add_feed_time":                   "加料时间",
			"add_feed_time_max_value":         execTime.AddFeedTime.MaxValue,
			"add_feed_time_up_middle_value":   execTime.AddFeedTime.UpMiddleValue,
			"add_feed_time_middle_value":      execTime.AddFeedTime.MiddleValue,
			"add_feed_time_down_middle_value": execTime.AddFeedTime.DownMiddleValue,
			"add_feed_time_min_value":         execTime.AddFeedTime.MinValue,
			"sprinkle_time":                   "撒料时间",
			"sprinkle_time_max_value":         execTime.SprinkleTime.MaxValue,
			"sprinkle_time_up_middle_value":   execTime.SprinkleTime.UpMiddleValue,
			"sprinkle_time_middle_value":      execTime.SprinkleTime.MiddleValue,
			"sprinkle_time_down_middle_value": execTime.SprinkleTime.DownMiddleValue,
			"sprinkle_time_min_value":         execTime.SprinkleTime.MinValue,
			"stir_time":                       "搅拌延迟时间",
			"stir_time_max_value":             execTime.StirTime.MaxValue,
			"stir_time_up_middle_value":       execTime.StirTime.UpMiddleValue,
			"stir_time_middle_value":          execTime.StirTime.MiddleValue,
			"stir_time_down_middle_value":     execTime.StirTime.DownMiddleValue,
			"stir_time_min_value":             execTime.StirTime.MinValue,
		}

		res.Data.TableList = append(res.Data.TableList, tableList)
	}

	return res, nil
}

func (s *StoreEntry) SprinkleFeedTime(ctx context.Context, req *operationPb.SprinkleFeedTimeRequest) (*model.SprinkleFeedTimeResponse, error) {
	res := &model.SprinkleFeedTimeResponse{
		Code: http.StatusOK,
		Msg:  "ok",
		Data: &model.SprinkleFeedTimeData{
			Chart: &model.SprinkleFeedTimeChart{
				Title:              make([]string, 0),
				SprinkleNumberList: make([][]int32, 0),
			},
			TableList: make([]*model.SprinkleFeedTimeTable, 0),
		},
	}
	pastureSprinkleDataList, err := s.PastureSprinkleFeedTime(ctx, req)
	if err != nil {
		return nil, xerr.WithStack(err)
	}

	tableList := make([]*model.SprinkleFeedTimeTable, 0)
	infoSprinkleNumber, errorSprinkleNumber := make([]int32, 0), make([]int32, 0)
	for pastureName, data := range pastureSprinkleDataList {
		sprinkleFeedTimeList := make(map[int32]map[int32][]int64, 0)
		for _, v := range data {
			tableList = append(tableList, &model.SprinkleFeedTimeTable{
				PastureName:             pastureName,
				BarnName:                v.FName,
				ClassNumber:             fmt.Sprintf("%d", v.Times),
				RealitySprinkleFeedTime: tool.TimeSub(v.InTime, v.ProcessTime),
			})
			realityTime := tool.TimeSub(v.InTime, v.ProcessTime)
			realityTimeUnix, _ := time.Parse(model.LayoutTime, realityTime)
			if sprinkleFeedTimeList[v.FBarId] == nil {
				sprinkleFeedTimeList[v.FBarId] = make(map[int32][]int64, 0)
			}
			sprinkleFeedTimeList[v.FBarId][v.Times] = append(sprinkleFeedTimeList[v.FBarId][v.Times], realityTimeUnix.Unix())
		}
		res.Data.Chart.Title = append(res.Data.Chart.Title, pastureName)

		infoNumber, errNumber := sprinkleExecTimeAnalysis(sprinkleFeedTimeList)
		infoSprinkleNumber = append(infoSprinkleNumber, infoNumber)
		errorSprinkleNumber = append(errorSprinkleNumber, errNumber)
	}
	res.Data.Chart.SprinkleNumberList = append(res.Data.Chart.SprinkleNumberList, infoSprinkleNumber, errorSprinkleNumber)
	res.Data.TableList = tableList
	return res, nil
}

func (s *StoreEntry) FeedMixedAndTmrName(ctx context.Context, req *operationPb.MixedCategoryTmrName) (*model.PastureCommonResponse, error) {
	groupPasture, err := s.GetGroupPastureListById(ctx, int64(req.PastureId))
	if err != nil {
		return nil, xerr.WithStack(err)
	}
	pastureId := req.PastureId
	if groupPasture.PastureId > 0 {
		pastureId = int32(groupPasture.PastureId)
	}
	body := &model.PastureCommonRequest{
		Name:       req.ApiName,
		ReturnType: "Map",
		ParamMaps: &model.MixedCategoryTmrNameParams{
			PastureId: fmt.Sprintf("%d", pastureId),
			StartTime: req.StartTime,
			EndTime:   req.EndTime,
		},
	}
	response := &model.PastureCommonResponse{Data: &model.PastureCommonData{}}
	if _, err := s.PastureHttpClient(ctx, model.UrlDataByName, int64(req.PastureId), body, response); err != nil {
		return nil, xerr.WithStack(err)
	}
	return response, nil
}

func sprinkleExecTimeAnalysis(sprinkleFeedTimeList map[int32]map[int32][]int64) (int32, int32) {
	var infoSprinkleNumber, errorSprinkleNumber int32 = 0, 0
	if len(sprinkleFeedTimeList) <= 0 {
		return infoSprinkleNumber, errorSprinkleNumber
	} else {
		for _, value := range sprinkleFeedTimeList {
			for _, execTimeList := range value {
				middleValue := tool.MedianInt64(execTimeList)
				for _, v := range execTimeList {
					if v >= middleValue-int64(compareTime) && v <= middleValue+int64(compareTime) {
						infoSprinkleNumber += 1
					} else {
						errorSprinkleNumber += 1
					}
				}
			}
		}
	}

	return infoSprinkleNumber, errorSprinkleNumber
}

func dashboardTopRand(req *operationPb.SearchAnalysisAccuracyRequest, data []*model.PastureTopData) []*model.PastureTopData {
	if req.TopRandStart < 0 || req.TopRandEnd < 0 || req.TopRandStart > req.TopRandEnd {
		return data
	}

	res := make([]*model.PastureTopData, 0)
	for _, v := range data {
		if v.Ratio >= float64(req.TopRandStart) && v.Ratio <= float64(req.TopRandEnd) {
			res = append(res, v)
		}
	}
	return res
}