package pig

import (
	"context"
	"errors"
	"fmt"

	"git.huangwc.com/pig/pig-farm-controller/internal/infra/logs"
	"git.huangwc.com/pig/pig-farm-controller/internal/infra/models"
	"git.huangwc.com/pig/pig-farm-controller/internal/infra/repository"

	"gorm.io/gorm"
)

// SickPigManager 定义了与病猪管理相关的操作接口。
// 这是一个领域服务，负责协调病猪记录、用药等业务逻辑。
type SickPigManager interface {
	// ProcessSickPigLog 处理病猪相关的日志事件。
	// log 包含事件的基本信息，如 PigBatchID, PenID, PigIDs, ChangeCount, Reason, TreatmentLocation, Remarks, OperatorID, HappenedAt。
	// Manager 内部会计算并填充 BeforeCount 和 AfterCount，并进行必要的业务校验和副作用处理。
	ProcessSickPigLog(ctx context.Context, tx *gorm.DB, log *models.PigSickLog) error

	// GetCurrentSickPigCount 获取指定批次当前患病猪只的总数
	GetCurrentSickPigCount(ctx context.Context, tx *gorm.DB, batchID uint32) (int, error)
}

// sickPigManager 是 SickPigManager 接口的具体实现。
// 它依赖于仓库接口来执行数据持久化操作。
type sickPigManager struct {
	ctx               context.Context
	sickLogRepo       repository.PigSickLogRepository
	medicationLogRepo repository.MedicationLogRepository
}

// NewSickPigManager 是 sickPigManager 的构造函数。
func NewSickPigManager(
	ctx context.Context,
	sickLogRepo repository.PigSickLogRepository,
	medicationLogRepo repository.MedicationLogRepository,
) SickPigManager {
	return &sickPigManager{
		ctx:               ctx,
		sickLogRepo:       sickLogRepo,
		medicationLogRepo: medicationLogRepo,
	}
}

func (s *sickPigManager) ProcessSickPigLog(ctx context.Context, tx *gorm.DB, log *models.PigSickLog) error {
	managerCtx := logs.AddFuncName(ctx, s.ctx, "ProcessSickPigLog")
	// 1. 输入校验
	if log == nil {
		return errors.New("病猪日志不能为空")
	}

	// 关键字段校验
	var missingFields []string
	if log.PigBatchID == 0 {
		missingFields = append(missingFields, "PigBatchID")
	}
	if log.ChangeCount == 0 {
		missingFields = append(missingFields, "ChangeCount")
	}
	if log.Reason == "" {
		missingFields = append(missingFields, "Reason")
	}
	if log.TreatmentLocation == "" {
		missingFields = append(missingFields, "TreatmentLocation")
	}
	if log.HappenedAt.IsZero() {
		missingFields = append(missingFields, "HappenedAt")
	}
	if log.OperatorID == 0 {
		missingFields = append(missingFields, "OperatorID")
	}
	if log.PenID == 0 {
		missingFields = append(missingFields, "PenID")
	}

	if len(missingFields) > 0 {
		return fmt.Errorf("以下关键字段不能为空或零值: %v", missingFields)
	}

	// 业务规则校验 - ChangeCount 与 Reason 的一致性
	switch log.Reason {
	case models.SickPigReasonTypeIllness, models.SickPigReasonTypeTransferIn:
		if log.ChangeCount < 0 {
			return fmt.Errorf("原因 '%s' 的 ChangeCount 必须为正数", log.Reason)
		}
	case models.SickPigReasonTypeRecovery, models.SickPigReasonTypeDeath, models.SickPigReasonTypeEliminate, models.SickPigReasonTypeTransferOut:
		if log.ChangeCount > 0 {
			return fmt.Errorf("原因 '%s' 的 ChangeCount 必须为负数", log.Reason)
		}
	case models.SickPigReasonTypeOther:
		// 其他原因，ChangeCount 可以是任意值，但不能为0
		if log.ChangeCount == 0 {
			return errors.New("原因 '其他' 的 ChangeCount 不能为零")
		}
	default:
		return fmt.Errorf("未知的病猪日志原因类型: %s", log.Reason)
	}

	// 2. 获取当前病猪数量 (BeforeCount)
	beforeCount, err := s.GetCurrentSickPigCount(managerCtx, tx, log.PigBatchID)
	if err != nil {
		return fmt.Errorf("获取批次 %d 当前病猪数量失败: %w", log.PigBatchID, err)
	}
	log.BeforeCount = beforeCount

	// 3. 计算变化后的数量 (AfterCount)
	log.AfterCount = log.BeforeCount + log.ChangeCount

	// 4. 业务规则校验 - 数量合法性
	if log.AfterCount < 0 {
		return fmt.Errorf("操作后病猪数量不能为负数，当前 %d，变化 %d", log.BeforeCount, log.ChangeCount)
	}

	// 5. 持久化 PigSickLog
	if err := s.sickLogRepo.CreatePigSickLogTx(managerCtx, tx, log); err != nil {
		return fmt.Errorf("创建 PigSickLog 失败: %w", err)
	}

	return nil
}

func (s *sickPigManager) GetCurrentSickPigCount(ctx context.Context, tx *gorm.DB, batchID uint32) (int, error) {
	managerCtx := logs.AddFuncName(ctx, s.ctx, "GetCurrentSickPigCount")
	lastLog, err := s.sickLogRepo.GetLastLogByBatchTx(managerCtx, tx, batchID)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return 0, nil // 如果没有找到任何日志，表示当前病猪数量为0
		}
		return 0, fmt.Errorf("获取批次 %d 的最新病猪日志失败: %w", batchID, err)
	}
	return lastLog.AfterCount, nil
}
