package backend

import (
	"context"
	"fmt"
	"kpt-pasture/model"
	"kpt-pasture/util"
	"net/http"
	"regexp"
	"strconv"
	"time"

	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
	"gitee.com/xuyiping_admin/pkg/xerr"
)

func (s *StoreEntry) CalvingCowList(ctx context.Context, req *pasturePb.ItemsRequest, pagination *pasturePb.PaginationModel) (*pasturePb.CalvingItemsResponse, error) {
	userModel, err := s.GetUserModel(ctx)
	if err != nil {
		return nil, xerr.WithStack(err)
	}
	calvingItems := make([]*pasturePb.CalvingItems, 0)
	count := int64(0)
	pref := s.DB.Table(fmt.Sprintf("%s as a", new(model.EventCalving).TableName())).
		Select(`a.id,a.cow_id,a.ear_number,a.status,b.breed_status,b.pen_id,ROUND(b.current_weight/100,2) as current_weight,DATE_FORMAT(FROM_UNIXTIME(last_mating_at), '%Y-%m-%d') AS mating_at_format,
		b.day_age,b.last_bull_number as bull_id,b.pen_name,DATEDIFF(NOW(),FROM_UNIXTIME(last_mating_at)) AS mating_age,DATE_FORMAT(FROM_UNIXTIME(a.plan_day), '%Y-%m-%d') AS plan_day`).
		Joins("left join cow as b on a.cow_id = b.id").
		Where("a.status = ?", pasturePb.IsShow_No).
		Where("b.admission_status = ?", pasturePb.AdmissionStatus_Admission).
		Where("a.pasture_id = ?", userModel.AppPasture.Id)

	if req.EndDay != "" {
		dateTime := util.TimeParseLocalEndUnix(req.EndDay)
		pref.Where("a.plan_day <= ?", dateTime)
	}

	if req.PenId > 0 {
		pref.Where("b.pen_id = ?", req.PenId)
	}

	if err = pref.Order("a.plan_day DESC").
		Count(&count).
		Limit(int(pagination.PageSize)).
		Offset(int(pagination.PageOffset)).
		Find(&calvingItems).Error; err != nil {
		return nil, xerr.WithStack(err)
	}

	breedStatusMap := s.CowBreedStatusMap()
	for _, v := range calvingItems {
		breedStatusName := ""
		if breedStatus, ok := breedStatusMap[v.BreedStatus]; ok {
			breedStatusName = breedStatus
		}
		v.BreedStatusName = breedStatusName
	}

	return &pasturePb.CalvingItemsResponse{
		Code: http.StatusOK,
		Msg:  "ok",
		Data: &pasturePb.CalvingItemsData{
			Total:    int32(count),
			Page:     pagination.Page,
			PageSize: pagination.PageSize,
			Header: map[string]string{
				"id":              "编号",
				"cowId":           "牛号",
				"earNumber":       "耳标号",
				"breedStatusName": "繁殖状态",
				"penName":         "栏舍",
				"lact":            "胎次",
				"matingAge":       "配后天数",
				"dayAge":          "日龄",
				"status":          "是否完成",
				"bullId":          "配种公牛号",
				"planDay":         "预产时间",
				"matingAtFormat":  "配种时间",
				"currentWeight":   "体重",
			},
			List: calvingItems,
		},
	}, nil
}

func (s *StoreEntry) DryMilkCowList(ctx context.Context, req *pasturePb.ItemsRequest, pagination *pasturePb.PaginationModel) (*pasturePb.DruMilkItemsResponse, error) {
	userModel, err := s.GetUserModel(ctx)
	if err != nil {
		return nil, xerr.WithStack(err)
	}
	dryMilkItems := make([]*pasturePb.DruMilkItems, 0)
	count := int64(0)
	pref := s.DB.Table(fmt.Sprintf("%s as a", new(model.EventDryMilk).TableName())).
		Select(`a.id,a.cow_id,a.ear_number,a.status,b.breed_status,b.pen_id,b.day_age,b.last_bull_number as bull_number,
b.pen_name,DATEDIFF(NOW(),FROM_UNIXTIME(last_mating_at)) AS mating_age,DATE_FORMAT(FROM_UNIXTIME(a.plan_day), '%Y-%m-%d') AS plan_day`).
		Joins("left join cow as b on a.cow_id = b.id").
		Where("a.status = ?", pasturePb.IsShow_No).
		Where("b.admission_status = ?", pasturePb.AdmissionStatus_Admission).
		Where("a.pasture_id = ?", userModel.AppPasture.Id)

	if req.EndDay != "" {
		dateTime := util.TimeParseLocalEndUnix(req.EndDay)
		pref.Where("a.plan_day <= ?", dateTime)
	}

	if req.PenId > 0 {
		pref.Where("b.pen_id = ?", req.PenId)
	}

	if err = pref.Order("a.plan_day DESC").
		Count(&count).
		Limit(int(pagination.PageSize)).
		Offset(int(pagination.PageOffset)).
		Find(&dryMilkItems).Error; err != nil {
		return nil, xerr.WithStack(err)
	}

	systemBasic, err := s.GetSystemBasicByName(ctx, userModel.AppPasture.Id, model.PregnancyAge)
	if err != nil {
		return nil, xerr.WithStack(err)
	}

	breedStatusMap := s.CowBreedStatusMap()
	for _, v := range dryMilkItems {
		breedStatusName := ""
		if breedStatus, ok := breedStatusMap[v.BreedStatus]; ok {
			breedStatusName = breedStatus
		}
		v.BreedStatusName = breedStatusName
		v.CalvingAtFormat = time.Now().AddDate(0, 0, int(systemBasic.MinValue-v.PregnancyAge)).Format(model.LayoutDate2)
	}

	return &pasturePb.DruMilkItemsResponse{
		Code: http.StatusOK,
		Msg:  "ok",
		Data: &pasturePb.DruMilkItemsData{
			Total:    int32(count),
			Page:     pagination.Page,
			PageSize: pagination.PageSize,
			Header: map[string]string{
				"id":              "编号",
				"cowId":           "牛号",
				"earNumber":       "耳标号",
				"breedStatusName": "繁殖状态",
				"penName":         "栏舍",
				"lact":            "胎次",
				"pregnancyAge":    "怀孕天数",
				"dayAge":          "日龄",
				"status":          "是否完成",
				"bullNumber":      "配种公牛号",
				"planDay":         "干奶时间",
				"calvingAtFormat": "预产日期",
			},
			List: dryMilkItems,
		},
	}, nil
}

// TreatmentCowList 治疗清单
func (s *StoreEntry) TreatmentCowList(ctx context.Context, req *pasturePb.ItemsRequest, pagination *pasturePb.PaginationModel) (interface{}, error) {
	userModel, err := s.GetUserModel(ctx)
	if err != nil {
		return nil, xerr.WithStack(err)
	}

	diseaseItems := make([]*model.EventCowDisease, 0)
	count := int64(0)

	pref := s.DB.Table(fmt.Sprintf("%s as a", new(model.EventCowDisease).TableName())).
		Joins(fmt.Sprintf("JOIN %s AS b on a.cow_id = b.id", new(model.Cow).TableName())).
		Where("a.pasture_id = ?", userModel.AppPasture.Id).
		Where("a.health_status IN (?)", []pasturePb.HealthStatus_Kind{pasturePb.HealthStatus_Disease, pasturePb.HealthStatus_Treatment})

	if req.PenId > 0 {
		pref.Where("b.pen_id = ?", req.PenId)
	}

	if err = pref.Order("a.disease_at DESC").
		Count(&count).
		Limit(int(pagination.PageSize)).
		Offset(int(pagination.PageOffset)).
		Find(&diseaseItems).Error; err != nil {
		return nil, xerr.WithStack(err)
	}

	return &pasturePb.EventCowDiseaseResponse{
		Code: http.StatusOK,
		Msg:  "ok",
		Data: &pasturePb.EventCowDiseaseData{
			List:     model.EventCowDiseaseSlice(diseaseItems).ToPB(s.HealthStatusMap()),
			Total:    int32(count),
			PageSize: pagination.PageSize,
			Page:     pagination.Page,
			Header: map[string]string{
				"id":                   "编号",
				"cowId":                "牛号",
				"earNumber":            "耳标",
				"diagnoseName":         "疾病名称",
				"healthStatus":         "健康状态",
				"lastPrescriptionName": "处方名称",
				"treatmentDays":        "治疗天数",
				"onsetDays":            "发病天数",
				"penName":              "栏舍名称",
			},
		},
	}, nil
}

// WorkOrderCowList 暂时不处理工单业务
func (s *StoreEntry) WorkOrderCowList(ctx context.Context, req *pasturePb.ItemsRequest, pagination *pasturePb.PaginationModel) (interface{}, error) {
	return nil, nil
}

// Paginate 函数用于对切片进行分页
func Paginate(slice []*pasturePb.CalendarToDoList, req *pasturePb.CalendarToDoRequest, pagination *pasturePb.PaginationModel) ([]*pasturePb.CalendarToDoList, int32) {
	newSlice := make([]*pasturePb.CalendarToDoList, 0)

	if req.CalendarType > 0 {
		calendarTypeName := CalendarTypeMap()[req.CalendarType]
		if len(calendarTypeName) > 0 {
			re := regexp.MustCompile(`[a-zA-Z]`) // 使用正则表达式替换匹配的字母为空字符串
			calendarTypeName = re.ReplaceAllString(calendarTypeName, "")
			for _, v := range slice {
				if v.CalendarTypeName != calendarTypeName {
					continue
				}
				newSlice = append(newSlice, v)
			}
		}
	} else {
		newSlice = append(newSlice, slice...)
	}

	if req.CowId > 0 {
		filteredSlice := make([]*pasturePb.CalendarToDoList, 0)
		for _, v := range newSlice {
			if v.CowId != req.CowId {
				continue
			}
			filteredSlice = append(filteredSlice, v)
		}
		newSlice = filteredSlice
	}
	total := int32(len(newSlice))
	// 计算起始索引
	start := (pagination.Page - 1) * pagination.PageSize

	// 如果起始索引超出切片长度,返回空切片
	if start >= int32(len(newSlice)) {
		return []*pasturePb.CalendarToDoList{}, total
	}

	// 计算结束索引
	end := start + pagination.PageSize

	// 如果结束索引超出切片长度,调整到切片末尾
	if end > int32(len(newSlice)) {
		end = int32(len(newSlice))
	}

	// 返回分页后的切片
	return newSlice[start:end], total
}

func ProgressList(dataList []*pasturePb.CalendarToDoList, toDayCompletedCountMap map[pasturePb.CalendarType_Kind]*pasturePb.ProgressList) map[string]*pasturePb.ProgressList {
	res := make(map[string]*pasturePb.ProgressList)
	dMap := map[pasturePb.CalendarType_Kind][]*pasturePb.CalendarToDoList{}

	for _, v := range dataList {
		dMap[v.CalendarType] = append(dMap[v.CalendarType], v)
	}

	for kind, cc := range toDayCompletedCountMap {
		if res[cc.CalendarName] == nil {
			res[cc.CalendarName] = &pasturePb.ProgressList{
				CalendarTypeKind: kind,
				CalendarName:     cc.CalendarName,
				Color:            model.CalendarTypeColorMap[kind],
				CompletedCount:   cc.CompletedCount,
				IncompleteTotal:  int32(len(dMap[kind])),
			}
		}

		if res[cc.CalendarName].IncompleteTotal > 0 && res[cc.CalendarName].CompletedCount > 0 {
			res[cc.CalendarName].Progress = strconv.FormatFloat(float64(res[cc.CalendarName].CompletedCount)/float64(res[cc.CalendarName].IncompleteTotal)*100, 'f', 2, 64)
		} else {
			res[cc.CalendarName].Progress = "0%"
		}
	}

	return res
}