package service

import (
	"context"
	"time"

	"git.huangwc.com/pig/pig-farm-controller/internal/app/dto"
	domain_pig "git.huangwc.com/pig/pig-farm-controller/internal/domain/pig"
	"git.huangwc.com/pig/pig-farm-controller/internal/infra/logs"
	"git.huangwc.com/pig/pig-farm-controller/internal/infra/models"
)

// PigBatchService 接口定义保持不变，继续作为应用层对外的契约。
type PigBatchService interface {
	CreatePigBatch(ctx context.Context, operatorID uint32, dto *dto.PigBatchCreateDTO) (*dto.PigBatchResponseDTO, error)
	GetPigBatch(ctx context.Context, id uint32) (*dto.PigBatchResponseDTO, error)
	UpdatePigBatch(ctx context.Context, id uint32, dto *dto.PigBatchUpdateDTO) (*dto.PigBatchResponseDTO, error)
	DeletePigBatch(ctx context.Context, id uint32) error
	ListPigBatches(ctx context.Context, isActive *bool) ([]*dto.PigBatchResponseDTO, error)

	// Pig Pen Management
	AssignEmptyPensToBatch(ctx context.Context, batchID uint32, penIDs []uint32, operatorID uint32) error
	ReclassifyPenToNewBatch(ctx context.Context, fromBatchID uint32, toBatchID uint32, penID uint32, operatorID uint32, remarks string) error
	RemoveEmptyPenFromBatch(ctx context.Context, batchID uint32, penID uint32) error
	MovePigsIntoPen(ctx context.Context, batchID uint32, toPenID uint32, quantity int, operatorID uint32, remarks string) error

	// Trade Sub-service
	SellPigs(ctx context.Context, batchID uint32, penID uint32, quantity int, unitPrice float32, tatalPrice float32, traderName string, tradeDate time.Time, remarks string, operatorID uint32) error
	BuyPigs(ctx context.Context, batchID uint32, penID uint32, quantity int, unitPrice float32, tatalPrice float32, traderName string, tradeDate time.Time, remarks string, operatorID uint32) error

	// Transfer Sub-service
	TransferPigsAcrossBatches(ctx context.Context, sourceBatchID uint32, destBatchID uint32, fromPenID uint32, toPenID uint32, quantity uint32, operatorID uint32, remarks string) error
	TransferPigsWithinBatch(ctx context.Context, batchID uint32, fromPenID uint32, toPenID uint32, quantity uint32, operatorID uint32, remarks string) error

	// Sick Pig Management
	RecordSickPigs(ctx context.Context, operatorID uint32, batchID uint32, penID uint32, quantity int, treatmentLocation models.PigBatchSickPigTreatmentLocation, happenedAt time.Time, remarks string) error
	RecordSickPigRecovery(ctx context.Context, operatorID uint32, batchID uint32, penID uint32, quantity int, treatmentLocation models.PigBatchSickPigTreatmentLocation, happenedAt time.Time, remarks string) error
	RecordSickPigDeath(ctx context.Context, operatorID uint32, batchID uint32, penID uint32, quantity int, treatmentLocation models.PigBatchSickPigTreatmentLocation, happenedAt time.Time, remarks string) error
	RecordSickPigCull(ctx context.Context, operatorID uint32, batchID uint32, penID uint32, quantity int, treatmentLocation models.PigBatchSickPigTreatmentLocation, happenedAt time.Time, remarks string) error

	// Normal Pig Management
	RecordDeath(ctx context.Context, operatorID uint32, batchID uint32, penID uint32, quantity int, happenedAt time.Time, remarks string) error
	RecordCull(ctx context.Context, operatorID uint32, batchID uint32, penID uint32, quantity int, happenedAt time.Time, remarks string) error
}

// pigBatchService 的实现现在依赖于领域服务接口。
type pigBatchService struct {
	ctx           context.Context
	domainService domain_pig.PigBatchService
}

// NewPigBatchService 构造函数被修改，以注入领域服务。
func NewPigBatchService(ctx context.Context, domainService domain_pig.PigBatchService) PigBatchService {
	return &pigBatchService{
		ctx:           ctx,
		domainService: domainService,
	}
}

// toPigBatchResponseDTO 负责将领域模型转换为应用层DTO，这个职责保留在应用层。
func (s *pigBatchService) toPigBatchResponseDTO(batch *models.PigBatch, currentTotalQuantity, currentTotalPigsInPens int) *dto.PigBatchResponseDTO {
	if batch == nil {
		return nil
	}
	return &dto.PigBatchResponseDTO{
		ID:                     batch.ID,
		BatchNumber:            batch.BatchNumber,
		OriginType:             batch.OriginType,
		StartDate:              batch.StartDate,
		EndDate:                batch.EndDate,
		InitialCount:           batch.InitialCount,
		Status:                 batch.Status,
		IsActive:               batch.IsActive(),
		CurrentTotalQuantity:   currentTotalQuantity,
		CurrentTotalPigsInPens: currentTotalPigsInPens,
		CreateTime:             batch.CreatedAt,
		UpdateTime:             batch.UpdatedAt,
	}
}

// CreatePigBatch 现在将请求委托给领域服务处理。
func (s *pigBatchService) CreatePigBatch(ctx context.Context, operatorID uint32, dto *dto.PigBatchCreateDTO) (*dto.PigBatchResponseDTO, error) {
	serviceCtx, logger := logs.Trace(ctx, s.ctx, "CreatePigBatch")
	// 1. DTO -> 领域模型
	batch := &models.PigBatch{
		BatchNumber:  dto.BatchNumber,
		OriginType:   dto.OriginType,
		StartDate:    dto.StartDate,
		InitialCount: dto.InitialCount,
		Status:       dto.Status,
	}

	// 2. 调用领域服务
	createdBatch, err := s.domainService.CreatePigBatch(serviceCtx, operatorID, batch)
	if err != nil {
		logger.Errorf("应用层: 创建猪批次失败: %v", err)
		return nil, MapDomainError(err)
	}

	// 3. 领域模型 -> DTO
	return s.toPigBatchResponseDTO(createdBatch, dto.InitialCount, 0), nil
}

// GetPigBatch 从领域服务获取数据并转换为DTO，同时处理错误转换。
func (s *pigBatchService) GetPigBatch(ctx context.Context, id uint32) (*dto.PigBatchResponseDTO, error) {
	serviceCtx, logger := logs.Trace(ctx, s.ctx, "GetPigBatch")
	batch, err := s.domainService.GetPigBatch(serviceCtx, id)
	if err != nil {
		logger.Warnf("应用层: 获取猪批次失败, ID: %d, 错误: %v", id, err)
		return nil, MapDomainError(err)
	}
	currentTotalQuantity, err := s.domainService.GetCurrentPigQuantity(serviceCtx, id)
	if err != nil {
		logger.Warnf("应用层: 获取猪批次总数失败, ID: %d, 错误: %v", id, err)
		return nil, MapDomainError(err)
	}
	currentTotalPigsInPens, err := s.domainService.GetTotalPigsInPensForBatch(serviceCtx, id)
	if err != nil {
		logger.Warnf("应用层: 获取猪批次存栏总数失败, ID: %d, 错误: %v", id, err)
		return nil, MapDomainError(err)
	}
	return s.toPigBatchResponseDTO(batch, currentTotalQuantity, currentTotalPigsInPens), nil
}

// UpdatePigBatch 协调获取、更新和保存的流程，并处理错误转换。
func (s *pigBatchService) UpdatePigBatch(ctx context.Context, id uint32, dto *dto.PigBatchUpdateDTO) (*dto.PigBatchResponseDTO, error) {
	serviceCtx, logger := logs.Trace(ctx, s.ctx, "UpdatePigBatch")
	// 1. 先获取最新的领域模型
	existingBatch, err := s.domainService.GetPigBatch(serviceCtx, id)
	if err != nil {
		logger.Warnf("应用层: 更新猪批次失败，获取原批次信息错误, ID: %d, 错误: %v", id, err)
		return nil, MapDomainError(err)
	}

	// 2. 将DTO中的变更应用到模型上
	if dto.BatchNumber != nil {
		existingBatch.BatchNumber = *dto.BatchNumber
	}
	if dto.OriginType != nil {
		existingBatch.OriginType = *dto.OriginType
	}
	if dto.StartDate != nil {
		existingBatch.StartDate = *dto.StartDate
	}
	if dto.EndDate != nil {
		existingBatch.EndDate = *dto.EndDate
	}
	if dto.InitialCount != nil {
		existingBatch.InitialCount = *dto.InitialCount
	}
	if dto.Status != nil {
		existingBatch.Status = *dto.Status
	}

	// 3. 调用领域服务执行更新
	updatedBatch, err := s.domainService.UpdatePigBatch(serviceCtx, existingBatch)
	if err != nil {
		logger.Errorf("应用层: 更新猪批次失败, ID: %d, 错误: %v", id, err)
		return nil, MapDomainError(err)
	}

	// 4. 填充猪群信息
	currentTotalQuantity, err := s.domainService.GetCurrentPigQuantity(serviceCtx, id)
	if err != nil {
		logger.Warnf("应用层: 获取猪批次总数失败, ID: %d, 错误: %v", id, err)
		return nil, MapDomainError(err)
	}
	currentTotalPigsInPens, err := s.domainService.GetTotalPigsInPensForBatch(serviceCtx, id)
	if err != nil {
		logger.Warnf("应用层: 获取猪批次存栏总数失败, ID: %d, 错误: %v", id, err)
		return nil, MapDomainError(err)
	}

	// 5. 转换并返回结果
	return s.toPigBatchResponseDTO(updatedBatch, currentTotalQuantity, currentTotalPigsInPens), nil
}

// DeletePigBatch 将删除操作委托给领域服务，并转换领域错误为应用层错误。
func (s *pigBatchService) DeletePigBatch(ctx context.Context, id uint32) error {
	serviceCtx, logger := logs.Trace(ctx, s.ctx, "DeletePigBatch")
	err := s.domainService.DeletePigBatch(serviceCtx, id)
	if err != nil {
		logger.Errorf("应用层: 删除猪批次失败, ID: %d, 错误: %v", id, err)
		return MapDomainError(err)
	}
	return nil
}

// ListPigBatches 从领域服务获取列表并进行转换。
func (s *pigBatchService) ListPigBatches(ctx context.Context, isActive *bool) ([]*dto.PigBatchResponseDTO, error) {
	serviceCtx, logger := logs.Trace(ctx, s.ctx, "ListPigBatches")
	batches, err := s.domainService.ListPigBatches(serviceCtx, isActive)
	if err != nil {
		logger.Errorf("应用层: 批量查询猪批次失败: %v", err)
		return nil, MapDomainError(err)
	}

	var responseDTOs []*dto.PigBatchResponseDTO
	for _, batch := range batches {
		currentTotalQuantity, err := s.domainService.GetCurrentPigQuantity(serviceCtx, batch.ID)
		if err != nil {
			logger.Warnf("应用层: 获取猪批次总数失败, ID: %d, 错误: %v", batch.ID, err)
			return nil, MapDomainError(err)
		}
		currentTotalPigsInPens, err := s.domainService.GetTotalPigsInPensForBatch(serviceCtx, batch.ID)
		if err != nil {
			logger.Warnf("应用层: 获取猪批次存栏总数失败, ID: %d, 错误: %v", batch.ID, err)
			return nil, MapDomainError(err)
		}
		responseDTOs = append(responseDTOs, s.toPigBatchResponseDTO(batch, currentTotalQuantity, currentTotalPigsInPens))
	}

	return responseDTOs, nil
}

// AssignEmptyPensToBatch 委托给领域服务
func (s *pigBatchService) AssignEmptyPensToBatch(ctx context.Context, batchID uint32, penIDs []uint32, operatorID uint32) error {
	serviceCtx, logger := logs.Trace(ctx, s.ctx, "AssignEmptyPensToBatch")
	err := s.domainService.AssignEmptyPensToBatch(serviceCtx, batchID, penIDs, operatorID)
	if err != nil {
		logger.Errorf("应用层: 为猪批次分配空栏失败, 批次ID: %d, 错误: %v", batchID, err)
		return MapDomainError(err)
	}
	return nil
}

// ReclassifyPenToNewBatch 委托给领域服务
func (s *pigBatchService) ReclassifyPenToNewBatch(ctx context.Context, fromBatchID uint32, toBatchID uint32, penID uint32, operatorID uint32, remarks string) error {
	serviceCtx, logger := logs.Trace(ctx, s.ctx, "ReclassifyPenToNewBatch")
	err := s.domainService.ReclassifyPenToNewBatch(serviceCtx, fromBatchID, toBatchID, penID, operatorID, remarks)
	if err != nil {
		logger.Errorf("应用层: 划拨猪栏到新批次失败, 源批次ID: %d, 错误: %v", fromBatchID, err)
		return MapDomainError(err)
	}
	return nil
}

// RemoveEmptyPenFromBatch 委托给领域服务
func (s *pigBatchService) RemoveEmptyPenFromBatch(ctx context.Context, batchID uint32, penID uint32) error {
	serviceCtx, logger := logs.Trace(ctx, s.ctx, "RemoveEmptyPenFromBatch")
	err := s.domainService.RemoveEmptyPenFromBatch(serviceCtx, batchID, penID)
	if err != nil {
		logger.Errorf("应用层: 从猪批次移除空栏失败, 批次ID: %d, 猪栏ID: %d, 错误: %v", batchID, penID, err)
		return MapDomainError(err)
	}
	return nil
}

// MovePigsIntoPen 委托给领域服务
func (s *pigBatchService) MovePigsIntoPen(ctx context.Context, batchID uint32, toPenID uint32, quantity int, operatorID uint32, remarks string) error {
	serviceCtx, logger := logs.Trace(ctx, s.ctx, "MovePigsIntoPen")
	err := s.domainService.MovePigsIntoPen(serviceCtx, batchID, toPenID, quantity, operatorID, remarks)
	if err != nil {
		logger.Errorf("应用层: 将猪只移入猪栏失败, 批次ID: %d, 目标猪栏ID: %d, 错误: %v", batchID, toPenID, err)
		return MapDomainError(err)
	}
	return nil
}

// 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, logger := logs.Trace(ctx, s.ctx, "SellPigs")
	err := s.domainService.SellPigs(serviceCtx, batchID, penID, quantity, unitPrice, tatalPrice, traderName, tradeDate, remarks, operatorID)
	if err != nil {
		logger.Errorf("应用层: 卖猪失败, 批次ID: %d, 错误: %v", batchID, err)
		return MapDomainError(err)
	}
	return nil
}

// BuyPigs 委托给领域服务
func (s *pigBatchService) BuyPigs(ctx context.Context, batchID uint32, penID uint32, quantity int, unitPrice float32, tatalPrice float32, traderName string, tradeDate time.Time, remarks string, operatorID uint32) error {
	serviceCtx, logger := logs.Trace(ctx, s.ctx, "BuyPigs")
	err := s.domainService.BuyPigs(serviceCtx, batchID, penID, quantity, unitPrice, tatalPrice, traderName, tradeDate, remarks, operatorID)
	if err != nil {
		logger.Errorf("应用层: 买猪失败, 批次ID: %d, 错误: %v", batchID, err)
		return MapDomainError(err)
	}
	return nil
}

// TransferPigsAcrossBatches 委托给领域服务
func (s *pigBatchService) TransferPigsAcrossBatches(ctx context.Context, sourceBatchID uint32, destBatchID uint32, fromPenID uint32, toPenID uint32, quantity uint32, operatorID uint32, remarks string) error {
	serviceCtx, logger := logs.Trace(ctx, s.ctx, "TransferPigsAcrossBatches")
	err := s.domainService.TransferPigsAcrossBatches(serviceCtx, sourceBatchID, destBatchID, fromPenID, toPenID, quantity, operatorID, remarks)
	if err != nil {
		logger.Errorf("应用层: 跨群调栏失败, 源批次ID: %d, 错误: %v", sourceBatchID, err)
		return MapDomainError(err)
	}
	return nil
}

// TransferPigsWithinBatch 委托给领域服务
func (s *pigBatchService) TransferPigsWithinBatch(ctx context.Context, batchID uint32, fromPenID uint32, toPenID uint32, quantity uint32, operatorID uint32, remarks string) error {
	serviceCtx, logger := logs.Trace(ctx, s.ctx, "TransferPigsWithinBatch")
	err := s.domainService.TransferPigsWithinBatch(serviceCtx, batchID, fromPenID, toPenID, quantity, operatorID, remarks)
	if err != nil {
		logger.Errorf("应用层: 群内调栏失败, 批次ID: %d, 错误: %v", batchID, err)
		return MapDomainError(err)
	}
	return nil
}

// RecordSickPigs 委托给领域服务
func (s *pigBatchService) RecordSickPigs(ctx context.Context, operatorID uint32, batchID uint32, penID uint32, quantity int, treatmentLocation models.PigBatchSickPigTreatmentLocation, happenedAt time.Time, remarks string) error {
	serviceCtx, logger := logs.Trace(ctx, s.ctx, "RecordSickPigs")
	err := s.domainService.RecordSickPigs(serviceCtx, operatorID, batchID, penID, quantity, treatmentLocation, happenedAt, remarks)
	if err != nil {
		logger.Errorf("应用层: 记录病猪事件失败, 批次ID: %d, 错误: %v", batchID, err)
		return MapDomainError(err)
	}
	return nil
}

// RecordSickPigRecovery 委托给领域服务
func (s *pigBatchService) RecordSickPigRecovery(ctx context.Context, operatorID uint32, batchID uint32, penID uint32, quantity int, treatmentLocation models.PigBatchSickPigTreatmentLocation, happenedAt time.Time, remarks string) error {
	serviceCtx, logger := logs.Trace(ctx, s.ctx, "RecordSickPigRecovery")
	err := s.domainService.RecordSickPigRecovery(serviceCtx, operatorID, batchID, penID, quantity, treatmentLocation, happenedAt, remarks)
	if err != nil {
		logger.Errorf("应用层: 记录病猪康复事件失败, 批次ID: %d, 错误: %v", batchID, err)
		return MapDomainError(err)
	}
	return nil
}

// RecordSickPigDeath 委托给领域服务
func (s *pigBatchService) RecordSickPigDeath(ctx context.Context, operatorID uint32, batchID uint32, penID uint32, quantity int, treatmentLocation models.PigBatchSickPigTreatmentLocation, happenedAt time.Time, remarks string) error {
	serviceCtx, logger := logs.Trace(ctx, s.ctx, "RecordSickPigDeath")
	err := s.domainService.RecordSickPigDeath(serviceCtx, operatorID, batchID, penID, quantity, treatmentLocation, happenedAt, remarks)
	if err != nil {
		logger.Errorf("应用层: 记录病猪死亡事件失败, 批次ID: %d, 错误: %v", batchID, err)
		return MapDomainError(err)
	}
	return nil
}

// RecordSickPigCull 委托给领域服务
func (s *pigBatchService) RecordSickPigCull(ctx context.Context, operatorID uint32, batchID uint32, penID uint32, quantity int, treatmentLocation models.PigBatchSickPigTreatmentLocation, happenedAt time.Time, remarks string) error {
	serviceCtx, logger := logs.Trace(ctx, s.ctx, "RecordSickPigCull")
	err := s.domainService.RecordSickPigCull(serviceCtx, operatorID, batchID, penID, quantity, treatmentLocation, happenedAt, remarks)
	if err != nil {
		logger.Errorf("应用层: 记录病猪淘汰事件失败, 批次ID: %d, 错误: %v", batchID, err)
		return MapDomainError(err)
	}
	return nil
}

// RecordDeath 委托给领域服务
func (s *pigBatchService) RecordDeath(ctx context.Context, operatorID uint32, batchID uint32, penID uint32, quantity int, happenedAt time.Time, remarks string) error {
	serviceCtx, logger := logs.Trace(ctx, s.ctx, "RecordDeath")
	err := s.domainService.RecordDeath(serviceCtx, operatorID, batchID, penID, quantity, happenedAt, remarks)
	if err != nil {
		logger.Errorf("应用层: 记录正常猪只死亡事件失败, 批次ID: %d, 错误: %v", batchID, err)
		return MapDomainError(err)
	}
	return nil
}

// RecordCull 委托给领域服务
func (s *pigBatchService) RecordCull(ctx context.Context, operatorID uint32, batchID uint32, penID uint32, quantity int, happenedAt time.Time, remarks string) error {
	serviceCtx, logger := logs.Trace(ctx, s.ctx, "RecordCull")
	err := s.domainService.RecordCull(serviceCtx, operatorID, batchID, penID, quantity, happenedAt, remarks)
	if err != nil {
		logger.Errorf("应用层: 记录正常猪只淘汰事件失败, 批次ID: %d, 错误: %v", batchID, err)
		return MapDomainError(err)
	}
	return nil
}
