package backend

import (
	"context"
	"errors"
	"fmt"
	"kpt-pasture/model"
	"strings"

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

	operationPb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/operation"

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

func (s *StoreEntry) GetUserModel(ctx context.Context) (*model.UserModel, error) {
	systemUser, err := s.GetCurrentSystemUser(ctx)
	if err != nil {
		return nil, xerr.WithStack(err)
	}
	appPasture, err := s.GetCurrentFarmInfo(ctx)
	if err != nil {
		return nil, xerr.WithStack(err)
	}

	systemUserPastureIds := strings.Split(systemUser.PastureIds, ",")
	if len(systemUserPastureIds) == 0 {
		return nil, xerr.Custom("当前用户未配置相关牧场数据,请联系管理员!")
	}

	var info bool
	for _, v := range systemUserPastureIds {
		if v == fmt.Sprintf("%d", appPasture.Id) {
			info = true
		}
	}
	if !info {
		return nil, xerr.Custom("该用户未没有该牧场操作权限,请联系管理员开通牧场权限")
	}

	return &model.UserModel{
		SystemUser: systemUser,
		AppPasture: appPasture,
	}, nil
}

func (s *StoreEntry) GetCurrentSystemUser(ctx context.Context) (*model.SystemUser, error) {
	// 解析token
	userName, err := s.GetCurrentUserName(ctx)
	if err != nil {
		return nil, xerr.WithStack(err)
	}
	// 根据用户token获取用户数据
	systemUser := &model.SystemUser{Name: userName}
	if err = s.DB.Model(new(model.SystemUser)).
		Where("name = ?", userName).
		Where("is_show = ? and is_delete = ?", pasturePb.IsShow_Ok, pasturePb.IsShow_Ok).
		First(systemUser).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, xerr.Custom("当前登录用户数据不存在")
		}
		zaplog.Error("GetCurrentSystemUser", zap.Any("err", err), zap.Any("userName", userName))
		return nil, xerr.Custom("用户登录信息有误,请退出重新登录")
	}
	return systemUser, nil
}

func (s *StoreEntry) GetCurrentFarmInfo(ctx context.Context) (*model.AppPastureList, error) {
	farmId := s.GetFarmId(ctx)
	if farmId == "" {
		return nil, xerr.Custom("请选择牧场信息")
	}
	appPasture, err := s.FindPastureByFarmId(ctx, farmId)
	if err != nil {
		return nil, xerr.WithStack(err)
	}
	return appPasture, nil
}

// GetCurrentUserName 获取当前用户名
func (s *StoreEntry) GetCurrentUserName(ctx context.Context) (string, error) {
	userNameInter := ctx.Value(CurrentUserName)
	if userNameInter == nil {
		return "", xerr.Customf("cannot userName")
	}

	if userName, ok := userNameInter.(string); ok {
		return userName, nil
	} else {
		return "", xerr.Customf("waring userName")
	}
}

// GetFarmId 获取当前牧场Id
func (s *StoreEntry) GetFarmId(ctx context.Context) string {
	farmId := ctx.Value(CurrentFarmId)
	if farmId == nil {
		return ""
	}

	if farmIdStr, ok := farmId.(string); ok {
		return farmIdStr
	}
	return ""
}

func (s *StoreEntry) GetSystemUserById(ctx context.Context, userId int64) (*model.SystemUser, error) {
	systemUser := &model.SystemUser{Id: userId}
	if err := s.DB.Model(new(model.SystemUser)).First(systemUser).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, xerr.Customf("该系统用户数据不存在: %d", userId)
		}
		return nil, xerr.WithStack(err)
	}
	return systemUser, nil
}

func (s *StoreEntry) SystemDeptList(ctx context.Context, pastureId int64) ([]*model.SystemDept, error) {
	deptList := make([]*model.SystemDept, 0)
	if err := s.DB.Model(new(model.SystemDept)).
		Where("is_delete = ?", pasturePb.IsShow_Ok).
		Find(&deptList).Error; err != nil {
		return nil, xerr.WithStack(err)
	}
	return deptList, nil
}

func (s *StoreEntry) GetPenById(ctx context.Context, pastureId int64, penId int32) (*model.Pen, error) {
	penData := &model.Pen{Id: penId}
	if err := s.DB.Model(new(model.Pen)).First(penData).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, xerr.Customf("该栏舍数据不存在: %d", penId)
		}
		return nil, xerr.WithStack(err)
	}
	return penData, nil
}

func (s *StoreEntry) GetPenList(ctx context.Context, pastureId int64) ([]*model.Pen, error) {
	penList := make([]*model.Pen, 0)
	if err := s.DB.Model(new(model.Pen)).
		Where("is_delete = ?", pasturePb.IsShow_Ok).
		Where("pasture_id = ?", pastureId).
		Find(&penList).Error; err != nil {
		return nil, xerr.WithStack(err)
	}
	return penList, nil
}

func (s *StoreEntry) PenMap(ctx context.Context, pastureId int64) map[int32]*model.Pen {
	penList, err := s.GetPenList(ctx, pastureId)
	if err != nil {
		zaplog.Error("GetPenList", zap.Any("err", err), zap.Any("pastureId", pastureId))
	}
	penMap := make(map[int32]*model.Pen)
	for _, v := range penList {
		penMap[v.Id] = v
	}
	return penMap
}

func (s *StoreEntry) GetCowInfoByCowId(ctx context.Context, pastureId, cowId int64) (*model.Cow, error) {
	cowData := &model.Cow{Id: cowId}
	if err := s.DB.Model(new(model.Cow)).
		Where("pasture_id = ?", pastureId).
		Where("admission_status = ?", pasturePb.AdmissionStatus_Admission).
		First(cowData).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, xerr.Customf("该牛只数据不存在: %d", cowId)
		} else {
			return nil, xerr.WithStack(err)
		}
	}
	return cowData, nil
}

func (s *StoreEntry) GetCowInfoByCowIds(ctx context.Context, pastureId int64, cowIds []int64) ([]*model.Cow, error) {
	cowList := make([]*model.Cow, 0)
	if err := s.DB.Model(&model.Cow{}).
		Where("pasture_id = ?", pastureId).
		Where("admission_status = ?", pasturePb.AdmissionStatus_Admission).
		Where("id IN ?", cowIds).
		Find(&cowList).Error; err != nil {
		return nil, xerr.WithStack(err)
	}
	return cowList, nil
}

func (s *StoreEntry) GetTransferReasonInfo(ctx context.Context, reasonId int64) (*model.ConfigTransferPenReason, error) {
	configTransferPenReasonData := &model.ConfigTransferPenReason{
		Id: reasonId,
	}
	if err := s.DB.Model(new(model.ConfigTransferPenReason)).First(configTransferPenReasonData).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, xerr.Customf("该转群原因数据不存在: %d", reasonId)
		}
		return nil, xerr.WithStack(err)
	}
	return configTransferPenReasonData, nil
}

func (s *StoreEntry) GetCowWeightByLastSecond(ctx context.Context, pastureId, cowId, lastWeightAt int64) (*model.EventWeight, error) {
	cowWeightData := &model.EventWeight{}
	if err := s.DB.Model(new(model.EventWeight)).
		Where("pasture_id = ?", pastureId).
		Where("cow_id = ?", cowId).
		Where("weight_at < ?", lastWeightAt).
		First(cowWeightData).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, xerr.Customf("该牛只体重数据不存在: %d", cowId)
		}
		return nil, xerr.WithStack(err)
	}
	return cowWeightData, nil
}

func (s *StoreEntry) GetDrugsById(ctx context.Context, pastureId, drugsId int64) (*model.Drugs, error) {
	drugs := &model.Drugs{Id: drugsId}
	if err := s.DB.Model(new(model.Drugs)).
		Where("pasture_id = ?", pastureId).
		First(drugs).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, xerr.Customf("该药品数据不存在: %d", drugsId)
		}
		return nil, xerr.WithStack(err)
	}
	return drugs, nil
}

func (s *StoreEntry) DiseaseTypeList(ctx context.Context) ([]*model.ConfigDiseaseType, error) {
	diseaseTypeList := make([]*model.ConfigDiseaseType, 0)
	if err := s.DB.Model(new(model.ConfigDiseaseType)).
		Where("is_show = ?", pasturePb.IsShow_Ok).
		Find(&diseaseTypeList).Error; err != nil {
		return nil, xerr.WithStack(err)
	}
	return diseaseTypeList, nil
}

func (s *StoreEntry) GetDiseaseById(ctx context.Context, pastureId int64, diseaseId int32) (*model.Disease, error) {
	newDisease := &model.Disease{}
	if err := s.DB.Model(new(model.Disease)).
		Where("pasture_id = ?", pastureId).
		Where("is_show = ?", pasturePb.IsShow_Ok).
		Where("id = ?", diseaseId).
		First(newDisease).Error; err != nil {
		return nil, xerr.WithStack(err)
	}
	return newDisease, nil
}

func (s *StoreEntry) DiseaseListByIds(ctx context.Context, pastureId int64, ids []int32) ([]*model.Disease, error) {
	diseaseList := make([]*model.Disease, 0)
	if err := s.DB.Model(new(model.Disease)).
		Where("pasture_id = ?", pastureId).
		Where("is_show = ?", pasturePb.IsShow_Ok).
		Where("id IN ?", ids).Find(&diseaseList).Error; err != nil {
		return nil, xerr.WithStack(err)
	}
	return diseaseList, nil
}

func (s *StoreEntry) GetPrescriptionById(ctx context.Context, pastureId int64, id int32) (*model.Prescription, error) {
	newPrescription := &model.Prescription{}
	if err := s.DB.Model(new(model.Prescription)).
		Where("id = ?", id).
		Where("pasture_id = ?", pastureId).
		Where("is_show = ?", pasturePb.IsShow_Ok).
		First(&newPrescription).Error; err != nil {
		return nil, xerr.WithStack(err)
	}
	return newPrescription, nil
}

func (s *StoreEntry) PrescriptionDrugsByPrescriptionId(ctx context.Context, pastureId int64, prescriptionId int32) ([]*model.PrescriptionDrugs, error) {
	newPrescriptionDrugsList := make([]*model.PrescriptionDrugs, 0)
	if err := s.DB.Model(new(model.PrescriptionDrugs)).
		Where("pasture_id = ?", pastureId).
		Where("prescription_id = ?", prescriptionId).
		Where("is_show = ?", pasturePb.IsShow_Ok).
		Find(&newPrescriptionDrugsList).Error; err != nil {
		return nil, xerr.WithStack(err)
	}
	return newPrescriptionDrugsList, nil
}

func (s *StoreEntry) GetImmunizationById(ctx context.Context, pastureId, planId int64) (*model.ImmunizationPlan, error) {
	immunizationPlan := &model.ImmunizationPlan{Id: planId}
	if err := s.DB.Model(new(model.ImmunizationPlan)).
		Where("pasture_id = ?", pastureId).
		Where("is_show = ?", pasturePb.IsShow_Ok).
		First(immunizationPlan).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, xerr.Customf("该免疫计划不存在: %d", planId)
		}
		return nil, xerr.WithStack(err)
	}
	return immunizationPlan, nil
}

func (s *StoreEntry) GetWorkOrderSubByWorkOrderId(ctx context.Context, workOrderId int64) ([]*model.WorkOrderSub, error) {
	workOrderSubList := make([]*model.WorkOrderSub, 0)
	if err := s.DB.Model(new(model.WorkOrderSub)).
		Where("work_order_id = ?", workOrderId).
		Find(&workOrderSubList).Error; err != nil {
		return nil, xerr.WithStack(err)
	}
	return workOrderSubList, nil
}

func (s *StoreEntry) GetEventCowSameTimeByCowId(ctx context.Context, pastureId, cowId int64) (*model.EventCowSameTime, error) {
	eventCowSameTime := &model.EventCowSameTime{}
	if err := s.DB.Model(new(model.EventCowSameTime)).
		Where("cow_id = ?", cowId).
		Where("pasture_id = ?", pastureId).
		Where("status = ?", pasturePb.IsShow_No).
		First(eventCowSameTime).Error; err != nil {
		return nil, xerr.WithStack(err)
	}
	return eventCowSameTime, nil
}

func (s *StoreEntry) SearchSystemDeptListByIds(ctx context.Context, ids []int64) ([]*model.SystemDept, error) {
	systemDeptList := make([]*model.SystemDept, 0)
	if err := s.DB.Model(new(model.SystemDept)).
		Where("is_show = ?", operationPb.IsShow_OK).
		Find(&systemDeptList, ids).Error; err != nil {
		return nil, xerr.WithStack(err)
	}
	return systemDeptList, nil
}

func (s *StoreEntry) GetSystemDeptListById(ctx context.Context, id int64) (*model.SystemDept, error) {
	systemDept := &model.SystemDept{Id: id}
	if err := s.DB.Model(new(model.SystemDept)).First(systemDept).Error; err != nil {
		return nil, xerr.WithStack(err)
	}
	return systemDept, nil
}

func (s *StoreEntry) GetSystemBasicByName(ctx context.Context, name string) (*model.SystemBasic, error) {
	systemBasic := &model.SystemBasic{}
	if err := s.DB.Model(new(model.SystemBasic)).
		Where("name = ?", name).
		Where("is_show = ?", pasturePb.IsShow_Ok).
		First(systemBasic).Error; err != nil {
		return nil, xerr.WithStack(err)
	}
	return systemBasic, nil
}

// FindLastEventMatingByCowId 根据cowId获取最近一次配种表信息
func (s *StoreEntry) FindLastEventMatingByCowId(ctx context.Context, pastureId, cowId int64) (*model.EventMating, error) {
	newEventMating := &model.EventMating{}
	if err := s.DB.Model(new(model.EventMating)).
		Where("cow_id = ?", cowId).
		Where("pasture_id = ?", pastureId).
		Order("id desc").
		First(newEventMating).Error; err != nil {
		return nil, xerr.WithStack(err)
	}
	return newEventMating, nil
}

func (s *StoreEntry) FindEventEstrusByCowId(ctx context.Context, pastureId, cowId int64) (*model.EventEstrus, bool, error) {
	newEventEstrus := &model.EventEstrus{}
	if err := s.DB.Model(new(model.EventEstrus)).
		Where("cow_id = ?", cowId).
		Where("pasture_id = ?", pastureId).
		Where("is_show = ? ", pasturePb.IsShow_Ok).
		First(newEventEstrus).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, false, nil
		} else {
			return nil, false, xerr.WithStack(err)
		}
	}
	return newEventEstrus, true, nil
}

func (s *StoreEntry) GetOutboundById(ctx context.Context, pastureId, id int64) (*model.Outbound, error) {
	res := &model.Outbound{}
	if err := s.DB.Model(new(model.Outbound)).Where("pasture_id = ?", pastureId).
		Where("id = ?", id).First(res).Error; err != nil {
		return nil, xerr.WithStack(err)
	}
	return res, nil
}

func (s *StoreEntry) GetOutboundDetailByOutboundId(ctx context.Context, id int64) ([]*model.OutboundDetail, error) {
	list := make([]*model.OutboundDetail, 0)
	if err := s.DB.Model(new(model.OutboundDetail)).
		Where("outbound_id = ?", id).
		Where("is_delete = ?", pasturePb.IsShow_Ok).
		Find(&list).Error; err != nil {
		return nil, xerr.WithStack(err)
	}
	return list, nil
}

func (s *StoreEntry) FindEventPregnantCheckIsExIstByCowId(ctx context.Context, cow *model.Cow) (*model.EventPregnantCheck, error) {
	newEventPregnantCheck := &model.EventPregnantCheck{}
	if err := s.DB.Model(new(model.EventPregnantCheck)).
		Where("cow_id = ?", cow.Id).
		Where("lact = ?", cow.Lact).
		Where("status = ?", pasturePb.IsShow_No).
		Order("id desc").
		First(newEventPregnantCheck).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, xerr.Customf("该牛只: %d 孕检数据未找到", cow.Id)
		} else {
			return nil, xerr.WithStack(err)
		}
	}
	return newEventPregnantCheck, nil
}

func (s *StoreEntry) DiseaseMaps(ctx context.Context) (map[int64]*model.Disease, error) {
	res := make(map[int64]*model.Disease)
	list := make([]*model.Disease, 0)
	if err := s.DB.Model(new(model.Disease)).Where("is_show = ?", pasturePb.IsShow_Ok).Find(&list).Error; err != nil {
		return nil, xerr.WithStack(err)
	}
	for _, v := range list {
		res[v.Id] = v
	}
	return res, nil
}

func (s *StoreEntry) NeckRingIsExist(ctx context.Context, pastureId int64, number string) (*model.NeckRing, bool, error) {
	neckRing := &model.NeckRing{}
	if err := s.DB.Model(new(model.NeckRing)).
		Where("neck_ring_number = ?", number).
		Where("pasture_id = ?", pastureId).
		First(neckRing).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, false, nil
		} else {
			return nil, false, err
		}
	}
	return neckRing, true, nil
}

func (s *StoreEntry) GetEventLogList(
	cowId int64, lact int32,
	eventCategoryId pasturePb.EventCategory_Kind,
	paginationModel *pasturePb.PaginationModel,
) ([]*model.EventCowLog, error) {
	eventLogList := make([]*model.EventCowLog, 0)
	newEventCowLog := &model.EventCowLog{CowId: cowId}
	pref := s.DB.Table(newEventCowLog.TableName()).
		Where("cow_id = ?", cowId)
	if lact >= 0 {
		pref.Where("lact = ?", lact)
	}

	if eventCategoryId > 0 {
		pref.Where("event_category_id = ?", eventCategoryId)
	}

	if err := pref.Order("id desc").
		Offset(int(paginationModel.PageOffset)).
		Limit(int(paginationModel.PageSize)).
		Find(&eventLogList).Error; err != nil {
		return nil, xerr.WithStack(err)
	}
	return eventLogList, nil
}

func (s *StoreEntry) FindIndicatorsDetailsList(ctx context.Context) ([]*model.IndicatorsDetails, error) {
	list := make([]*model.IndicatorsDetails, 0)
	if err := s.DB.Model(new(model.IndicatorsDetails)).Find(&list).Error; err != nil {
		return nil, xerr.WithStack(err)
	}
	return list, nil
}
func (s *StoreEntry) GetCowLastEvent(pastureId, cowId int64, eventCategoryId pasturePb.EventCategory_Kind) *model.EventCowLog {
	newEventCowLog := &model.EventCowLog{CowId: cowId}
	pref := s.DB.Table(newEventCowLog.TableName()).
		Where("cow_id = ?", cowId).Where("pasture_id = ?", pastureId)
	if eventCategoryId > 0 {
		pref.Where("event_category_id = ?", eventCategoryId)
	}

	if err := pref.Order("id desc").First(newEventCowLog); err != nil {
		return nil
	}
	return newEventCowLog
}