package pig

import (
	"context"
	"errors"
	"fmt"
	"time"

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

	"gorm.io/gorm"
)

// SellPigs 处理批量销售猪的业务逻辑。
func (s *pigBatchService) SellPigs(ctx context.Context, batchID uint32, penID uint32, quantity int, unitPrice float32, tatalPrice float32, traderName string, tradeDate time.Time, remarks string, operatorID uint32) error {
	serviceCtx := logs.AddFuncName(ctx, s.ctx, "SellPigs")
	return s.uow.ExecuteInTransaction(serviceCtx, func(tx *gorm.DB) error {
		if quantity <= 0 {
			return errors.New("销售数量必须大于0")
		}

		// 1. 校验猪栏信息
		pen, err := s.transferSvc.GetPenByID(serviceCtx, tx, penID)
		if err != nil {
			if errors.Is(err, gorm.ErrRecordNotFound) {
				return ErrPenNotFound
			}
			return fmt.Errorf("获取猪栏 %d 信息失败: %w", penID, err)
		}

		// 校验猪栏是否属于该批次
		if pen.PigBatchID == nil || *pen.PigBatchID != batchID {
			return ErrPenNotAssociatedWithBatch
		}

		// 2. 业务校验：检查销售数量是否超过猪栏当前猪只数
		currentPigsInPen, err := s.transferSvc.GetCurrentPigsInPen(serviceCtx, tx, penID)
		if err != nil {
			return fmt.Errorf("获取猪栏 %d 当前猪只数失败: %w", penID, err)
		}

		if quantity > currentPigsInPen {
			return fmt.Errorf("销售数量 %d 超过猪栏 %d 当前猪只数 %d", quantity, penID, currentPigsInPen)
		}

		// 3. 记录销售交易 (财务)
		sale := &models.PigSale{
			PigBatchID: batchID,
			SaleDate:   tradeDate,
			Buyer:      traderName,
			Quantity:   quantity,
			UnitPrice:  unitPrice,
			TotalPrice: tatalPrice, // 总价不一定是单价x数量, 所以要传进来
			Remarks:    remarks,
			OperatorID: operatorID,
		}
		if err := s.tradeSvc.SellPig(serviceCtx, tx, sale); err != nil {
			return fmt.Errorf("记录销售交易失败: %w", err)
		}

		// 4. 创建猪只转移日志 (物理)
		transferLog := &models.PigTransferLog{
			TransferTime: tradeDate,
			PigBatchID:   batchID,
			PenID:        penID,
			Quantity:     -quantity, // 销售导致数量减少
			Type:         models.PigTransferTypeSale,
			OperatorID:   operatorID,
			Remarks:      fmt.Sprintf("销售给 %s", traderName),
		}
		if err := s.transferSvc.LogTransfer(serviceCtx, tx, transferLog); err != nil {
			return fmt.Errorf("创建猪只转移日志失败: %w", err)
		}

		// 5. 记录批次数量变更日志 (逻辑)
		if err := s.updatePigBatchQuantityTx(serviceCtx, tx, operatorID, batchID, models.ChangeTypeSale, -quantity,
			fmt.Sprintf("猪批次 %d 从猪栏 %d 销售 %d 头猪给 %s", batchID, penID, quantity, traderName),
			tradeDate); err != nil {
			return fmt.Errorf("更新猪批次数量失败: %w", err)
		}

		return nil
	})
}

// BuyPigs 处理批量购买猪的业务逻辑。
func (s *pigBatchService) BuyPigs(ctx context.Context, batchID uint32, penID uint32, quantity int, unitPrice float32, totalPrice float32, traderName string, tradeDate time.Time, remarks string, operatorID uint32) error {
	serviceCtx := logs.AddFuncName(ctx, s.ctx, "BuyPigs")
	return s.uow.ExecuteInTransaction(serviceCtx, func(tx *gorm.DB) error {
		if quantity <= 0 {
			return errors.New("采购数量必须大于0")
		}

		// 1. 校验猪栏信息
		pen, err := s.transferSvc.GetPenByID(serviceCtx, tx, penID)
		if err != nil {
			if errors.Is(err, gorm.ErrRecordNotFound) {
				return ErrPenNotFound
			}
			return fmt.Errorf("获取猪栏 %d 信息失败: %w", penID, err)
		}

		// 校验猪栏是否属于该批次
		if pen.PigBatchID == nil || *pen.PigBatchID != batchID {
			return ErrPenNotAssociatedWithBatch
		}

		// 2. 业务校验：检查猪栏容量，如果超出，在备注中记录警告
		currentPigsInPen, err := s.transferSvc.GetCurrentPigsInPen(serviceCtx, tx, penID)
		if err != nil {
			return fmt.Errorf("获取猪栏 %d 当前猪只数失败: %w", penID, err)
		}

		transferRemarks := fmt.Sprintf("从 %s 采购", traderName)
		if currentPigsInPen+quantity > pen.Capacity {
			warning := fmt.Sprintf("[警告]猪栏容量超出: 当前 %d, 采购 %d, 容量 %d.", currentPigsInPen, quantity, pen.Capacity)
			transferRemarks = fmt.Sprintf("%s %s", transferRemarks, warning)
		}

		// 3. 记录采购交易 (财务)
		purchase := &models.PigPurchase{
			PigBatchID:   batchID,
			PurchaseDate: tradeDate,
			Supplier:     traderName,
			Quantity:     quantity,
			UnitPrice:    unitPrice,
			TotalPrice:   totalPrice, // 总价不一定是单价x数量, 所以要传进来
			Remarks:      remarks,    // 用户传入的备注
			OperatorID:   operatorID,
		}
		if err := s.tradeSvc.BuyPig(serviceCtx, tx, purchase); err != nil {
			return fmt.Errorf("记录采购交易失败: %w", err)
		}

		// 4. 创建猪只转移日志 (物理)
		transferLog := &models.PigTransferLog{
			TransferTime: tradeDate,
			PigBatchID:   batchID,
			PenID:        penID,
			Quantity:     quantity, // 采购导致数量增加
			Type:         models.PigTransferTypePurchase,
			OperatorID:   operatorID,
			Remarks:      transferRemarks, // 包含系统生成的备注和潜在的警告
		}
		if err := s.transferSvc.LogTransfer(serviceCtx, tx, transferLog); err != nil {
			return fmt.Errorf("创建猪只转移日志失败: %w", err)
		}

		// 5. 记录批次数量变更日志 (逻辑)
		if err := s.updatePigBatchQuantityTx(serviceCtx, tx, operatorID, batchID, models.ChangeTypeBuy, quantity,
			fmt.Sprintf("猪批次 %d 在猪栏 %d 采购 %d 头猪从 %s", batchID, penID, quantity, traderName),
			tradeDate); err != nil {
			return fmt.Errorf("更新猪批次数量失败: %w", err)
		}

		return nil
	})
}
