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"
)

// --- 领域服务实现 ---

// CreatePigBatch 实现了创建猪批次的逻辑，并同时创建初始批次日志。
func (s *pigBatchService) CreatePigBatch(ctx context.Context, operatorID uint32, batch *models.PigBatch) (*models.PigBatch, error) {
	serviceCtx := logs.AddFuncName(ctx, s.ctx, "CreatePigBatch")
	// 业务规则可以在这里添加，例如检查批次号是否唯一等

	var createdBatch *models.PigBatch
	err := s.uow.ExecuteInTransaction(serviceCtx, func(tx *gorm.DB) error {
		// 1. 创建猪批次
		// 注意: 此处依赖一个假设存在的 pigBatchRepo.CreatePigBatchTx 方法
		var err error
		createdBatch, err = s.pigBatchRepo.CreatePigBatchTx(serviceCtx, tx, batch)
		if err != nil {
			return fmt.Errorf("创建猪批次失败: %w", err)
		}

		// 2. 创建初始批次日志
		initialLog := &models.PigBatchLog{
			PigBatchID:  createdBatch.ID,
			HappenedAt:  time.Now(),
			ChangeType:  models.ChangeTypeCorrection, // 初始创建可视为一种校正
			ChangeCount: createdBatch.InitialCount,
			Reason:      fmt.Sprintf("创建了新的猪批次 %s，初始数量 %d", createdBatch.BatchNumber, createdBatch.InitialCount),
			BeforeCount: 0, // 初始创建前数量为0
			AfterCount:  createdBatch.InitialCount,
			OperatorID:  operatorID,
		}

		// 3. 记录批次日志
		if err := s.pigBatchLogRepo.CreateTx(serviceCtx, tx, initialLog); err != nil {
			return fmt.Errorf("记录初始批次日志失败: %w", err)
		}

		return nil
	})

	if err != nil {
		return nil, err
	}

	return createdBatch, nil
}

// GetPigBatch 实现了获取单个猪批次的逻辑。
func (s *pigBatchService) GetPigBatch(ctx context.Context, id uint32) (*models.PigBatch, error) {
	serviceCtx := logs.AddFuncName(ctx, s.ctx, "GetPigBatch")
	batch, err := s.pigBatchRepo.GetPigBatchByID(serviceCtx, id)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, ErrPigBatchNotFound
		}
		return nil, err
	}
	return batch, nil
}

// UpdatePigBatch 实现了更新猪批次的逻辑。
func (s *pigBatchService) UpdatePigBatch(ctx context.Context, batch *models.PigBatch) (*models.PigBatch, error) {
	serviceCtx := logs.AddFuncName(ctx, s.ctx, "UpdatePigBatch")
	// 可以在这里添加更新前的业务校验
	updatedBatch, rowsAffected, err := s.pigBatchRepo.UpdatePigBatch(serviceCtx, batch)
	if err != nil {
		return nil, err
	}
	if rowsAffected == 0 {
		return nil, ErrPigBatchNotFound // 如果没有行被更新，可能意味着记录不存在
	}
	return updatedBatch, nil
}

// DeletePigBatch 实现了删除猪批次的逻辑，并包含业务规则校验。
func (s *pigBatchService) DeletePigBatch(ctx context.Context, id uint32) error {
	serviceCtx := logs.AddFuncName(ctx, s.ctx, "DeletePigBatch")
	return s.uow.ExecuteInTransaction(serviceCtx, func(tx *gorm.DB) error {
		// 1. 获取猪批次信息
		batch, err := s.pigBatchRepo.GetPigBatchByIDTx(serviceCtx, tx, id) // 使用事务内方法
		if err != nil {
			if errors.Is(err, gorm.ErrRecordNotFound) {
				return ErrPigBatchNotFound
			}
			return err
		}

		// 2. 核心业务规则：检查猪批次是否为活跃状态
		if batch.IsActive() {
			return ErrPigBatchActive // 如果活跃，则不允许删除
		}

		// 3. 释放所有关联的猪栏
		// 获取该批次下所有猪栏
		pensInBatch, err := s.transferSvc.GetPensByBatchID(serviceCtx, tx, id)
		if err != nil {
			return fmt.Errorf("获取猪批次 %d 关联猪栏失败: %w", id, err)
		}

		// 逐一释放猪栏
		for _, pen := range pensInBatch {
			if err := s.transferSvc.ReleasePen(serviceCtx, tx, pen.ID); err != nil {
				return fmt.Errorf("释放猪栏 %d 失败: %w", pen.ID, err)
			}
		}

		// 4. 执行删除猪批次
		rowsAffected, err := s.pigBatchRepo.DeletePigBatchTx(serviceCtx, tx, id)
		if err != nil {
			return err
		}
		if rowsAffected == 0 {
			return ErrPigBatchNotFound
		}

		return nil
	})
}

// ListPigBatches 实现了批量查询猪批次的逻辑。
func (s *pigBatchService) ListPigBatches(ctx context.Context, isActive *bool) ([]*models.PigBatch, error) {
	serviceCtx := logs.AddFuncName(ctx, s.ctx, "ListPigBatches")
	return s.pigBatchRepo.ListPigBatches(serviceCtx, isActive)
}

// GetCurrentPigQuantity 实现了获取指定猪批次的当前猪只数量的逻辑。
func (s *pigBatchService) GetCurrentPigQuantity(ctx context.Context, batchID uint32) (int, error) {
	serviceCtx := logs.AddFuncName(ctx, s.ctx, "GetCurrentPigQuantity")
	var getErr error
	var quantity int
	err := s.uow.ExecuteInTransaction(serviceCtx, func(tx *gorm.DB) error {
		quantity, getErr = s.getCurrentPigQuantityTx(serviceCtx, tx, batchID)
		return getErr
	})
	if err != nil {
		return 0, err
	}
	return quantity, nil
}

// getCurrentPigQuantityTx 实现了获取指定猪批次的当前猪只数量的逻辑。
func (s *pigBatchService) getCurrentPigQuantityTx(ctx context.Context, tx *gorm.DB, batchID uint32) (int, error) {
	serviceCtx := logs.AddFuncName(ctx, s.ctx, "getCurrentPigQuantityTx")
	// 1. 获取猪批次初始信息
	batch, err := s.pigBatchRepo.GetPigBatchByIDTx(serviceCtx, tx, batchID)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return 0, ErrPigBatchNotFound
		}
		return 0, fmt.Errorf("获取猪批次 %d 初始信息失败: %w", batchID, err)
	}

	// 2. 尝试获取该批次的最后一条日志记录
	lastLog, err := s.pigBatchLogRepo.GetLastLogByBatchIDTx(serviceCtx, tx, batchID)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			// 如果没有找到任何日志记录（除了初始创建），则当前数量就是初始数量
			return batch.InitialCount, nil
		}
		return 0, fmt.Errorf("获取猪批次 %d 最后一条日志失败: %w", batchID, err)
	}

	// 3. 如果找到最后一条日志，则当前数量为该日志的 AfterCount
	return lastLog.AfterCount, nil
}

func (s *pigBatchService) UpdatePigBatchQuantity(ctx context.Context, operatorID uint32, batchID uint32, changeType models.LogChangeType, changeAmount int, changeReason string, happenedAt time.Time) error {
	serviceCtx := logs.AddFuncName(ctx, s.ctx, "UpdatePigBatchQuantity")
	return s.uow.ExecuteInTransaction(serviceCtx, func(tx *gorm.DB) error {
		return s.updatePigBatchQuantityTx(serviceCtx, tx, operatorID, batchID, changeType, changeAmount, changeReason, happenedAt)
	})
}

func (s *pigBatchService) updatePigBatchQuantityTx(ctx context.Context, tx *gorm.DB, operatorID uint32, batchID uint32, changeType models.LogChangeType, changeAmount int, changeReason string, happenedAt time.Time) error {
	serviceCtx := logs.AddFuncName(ctx, s.ctx, "updatePigBatchQuantityTx")
	lastLog, err := s.pigBatchLogRepo.GetLastLogByBatchIDTx(serviceCtx, tx, batchID)
	if err != nil {
		return err
	}
	// 检查数量不应该减到小于零
	if changeAmount < 0 {
		if lastLog.AfterCount+changeAmount < 0 {
			return ErrInvalidOperation
		}
	}
	pigBatchLog := &models.PigBatchLog{
		PigBatchID:  batchID,
		ChangeType:  changeType,
		ChangeCount: changeAmount,
		Reason:      changeReason,
		BeforeCount: lastLog.AfterCount,
		AfterCount:  lastLog.AfterCount + changeAmount,
		OperatorID:  operatorID,
		HappenedAt:  happenedAt,
	}
	return s.pigBatchLogRepo.CreateTx(serviceCtx, tx, pigBatchLog)
}
