package service

import (
	"context"
	"errors"
	"fmt"

	"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"
	"git.huangwc.com/pig/pig-farm-controller/internal/infra/repository"

	"gorm.io/gorm"
)

// PigFarmService 提供了猪场资产管理的业务逻辑
type PigFarmService interface {
	// PigHouse methods
	CreatePigHouse(ctx context.Context, name, description string) (*dto.PigHouseResponse, error)
	GetPigHouseByID(ctx context.Context, id uint32) (*dto.PigHouseResponse, error)
	ListPigHouses(ctx context.Context) ([]dto.PigHouseResponse, error)
	UpdatePigHouse(ctx context.Context, id uint32, name, description string) (*dto.PigHouseResponse, error)
	DeletePigHouse(ctx context.Context, id uint32) error

	// Pen methods
	CreatePen(ctx context.Context, penNumber string, houseID uint32, capacity int) (*dto.PenResponse, error)
	GetPenByID(ctx context.Context, id uint32) (*dto.PenResponse, error)
	ListPens(ctx context.Context) ([]*dto.PenResponse, error)
	UpdatePen(ctx context.Context, id uint32, penNumber string, houseID uint32, capacity int, status models.PenStatus) (*dto.PenResponse, error)
	DeletePen(ctx context.Context, id uint32) error
	// UpdatePenStatus 更新猪栏状态
	UpdatePenStatus(ctx context.Context, id uint32, newStatus models.PenStatus) (*dto.PenResponse, error)
}

type pigFarmService struct {
	ctx             context.Context
	farmRepository  repository.PigFarmRepository
	penRepository   repository.PigPenRepository
	batchRepository repository.PigBatchRepository
	pigBatchService domain_pig.PigBatchService
	uow             repository.UnitOfWork // 工作单元，用于事务管理
}

// NewPigFarmService 创建一个新的 PigFarmService 实例
func NewPigFarmService(ctx context.Context,
	farmRepository repository.PigFarmRepository,
	penRepository repository.PigPenRepository,
	batchRepository repository.PigBatchRepository,
	pigBatchService domain_pig.PigBatchService,
	uow repository.UnitOfWork,
) PigFarmService {
	return &pigFarmService{
		ctx:             ctx,
		farmRepository:  farmRepository,
		penRepository:   penRepository,
		batchRepository: batchRepository,
		pigBatchService: pigBatchService,
		uow:             uow,
	}
}

// --- PigHouse Implementation ---

func (s *pigFarmService) CreatePigHouse(ctx context.Context, name, description string) (*dto.PigHouseResponse, error) {
	serviceCtx := logs.AddFuncName(ctx, s.ctx, "CreatePigHouse")
	house := &models.PigHouse{
		Name:        name,
		Description: description,
	}
	err := s.farmRepository.CreatePigHouse(serviceCtx, house)
	if err != nil {
		return nil, err
	}
	return &dto.PigHouseResponse{
		ID:          house.ID,
		Name:        house.Name,
		Description: house.Description,
	}, nil
}

func (s *pigFarmService) GetPigHouseByID(ctx context.Context, id uint32) (*dto.PigHouseResponse, error) {
	serviceCtx := logs.AddFuncName(ctx, s.ctx, "GetPigHouseByID")
	house, err := s.farmRepository.GetPigHouseByID(serviceCtx, id)
	if err != nil {
		return nil, err
	}
	return &dto.PigHouseResponse{
		ID:          house.ID,
		Name:        house.Name,
		Description: house.Description,
	}, nil
}

func (s *pigFarmService) ListPigHouses(ctx context.Context) ([]dto.PigHouseResponse, error) {
	serviceCtx := logs.AddFuncName(ctx, s.ctx, "ListPigHouses")
	houses, err := s.farmRepository.ListPigHouses(serviceCtx)
	if err != nil {
		return nil, err
	}
	var resp []dto.PigHouseResponse
	for _, house := range houses {
		resp = append(resp, dto.PigHouseResponse{
			ID:          house.ID,
			Name:        house.Name,
			Description: house.Description,
		})
	}
	return resp, nil
}

func (s *pigFarmService) UpdatePigHouse(ctx context.Context, id uint32, name, description string) (*dto.PigHouseResponse, error) {
	serviceCtx := logs.AddFuncName(ctx, s.ctx, "UpdatePigHouse")
	house := &models.PigHouse{
		Model:       models.Model{ID: id},
		Name:        name,
		Description: description,
	}
	rowsAffected, err := s.farmRepository.UpdatePigHouse(serviceCtx, house)
	if err != nil {
		return nil, err
	}
	if rowsAffected == 0 {
		return nil, ErrHouseNotFound
	}
	// 返回更新后的完整信息
	updatedHouse, err := s.farmRepository.GetPigHouseByID(serviceCtx, id)
	if err != nil {
		return nil, err
	}
	return &dto.PigHouseResponse{
		ID:          updatedHouse.ID,
		Name:        updatedHouse.Name,
		Description: updatedHouse.Description,
	}, nil
}

func (s *pigFarmService) DeletePigHouse(ctx context.Context, id uint32) error {
	serviceCtx := logs.AddFuncName(ctx, s.ctx, "DeletePigHouse")
	// 业务逻辑：检查猪舍是否包含猪栏
	penCount, err := s.farmRepository.CountPensInHouse(serviceCtx, id)
	if err != nil {
		return err
	}
	if penCount > 0 {
		return ErrHouseContainsPens
	}

	// 调用仓库层进行删除
	rowsAffected, err := s.farmRepository.DeletePigHouse(serviceCtx, id)
	if err != nil {
		return err
	}
	if rowsAffected == 0 {
		return ErrHouseNotFound
	}
	return nil
}

// --- Pen Implementation ---

func (s *pigFarmService) CreatePen(ctx context.Context, penNumber string, houseID uint32, capacity int) (*dto.PenResponse, error) {
	serviceCtx := logs.AddFuncName(ctx, s.ctx, "CreatePen")
	// 业务逻辑：验证所属猪舍是否存在
	_, err := s.farmRepository.GetPigHouseByID(serviceCtx, houseID)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, ErrHouseNotFound
		}
		return nil, err
	}

	pen := &models.Pen{
		PenNumber: penNumber,
		HouseID:   houseID,
		Capacity:  capacity,
		Status:    models.PenStatusEmpty,
	}
	err = s.penRepository.CreatePen(serviceCtx, pen)
	if err != nil {
		return nil, err
	}
	return &dto.PenResponse{
		ID:        pen.ID,
		PenNumber: pen.PenNumber,
		HouseID:   pen.HouseID,
		Capacity:  pen.Capacity,
		Status:    pen.Status,
	}, nil
}

func (s *pigFarmService) GetPenByID(ctx context.Context, id uint32) (*dto.PenResponse, error) {
	serviceCtx, logger := logs.Trace(ctx, s.ctx, "GetPenByID")
	pen, err := s.penRepository.GetPenByID(serviceCtx, id)
	if err != nil {
		return nil, err
	}

	currentPigCount, err := s.pigBatchService.GetCurrentPigsInPen(serviceCtx, id)
	if err != nil {
		logger.Errorf("获取猪栏 %d 存栏量失败: %v", id, err)
		currentPigCount = 0 // 如果获取计数时出错，则默认为0
	}

	response := &dto.PenResponse{
		ID:              pen.ID,
		PenNumber:       pen.PenNumber,
		HouseID:         pen.HouseID,
		Capacity:        pen.Capacity,
		Status:          pen.Status,
		CurrentPigCount: currentPigCount,
	}

	if pen.PigBatchID != nil {
		response.PigBatchID = pen.PigBatchID
	}

	return response, nil
}

func (s *pigFarmService) ListPens(ctx context.Context) ([]*dto.PenResponse, error) {
	serviceCtx, logger := logs.Trace(ctx, s.ctx, "ListPens")
	pens, err := s.penRepository.ListPens(serviceCtx)
	if err != nil {
		return nil, err
	}

	var response []*dto.PenResponse
	for _, pen := range pens {
		currentPigCount, err := s.pigBatchService.GetCurrentPigsInPen(serviceCtx, pen.ID)
		if err != nil {
			logger.Errorf("获取猪栏 %d 存栏量失败: %v", pen.ID, err)
			currentPigCount = 0 // 如果获取计数时出错，则默认为0
		}

		penResponse := &dto.PenResponse{
			ID:              pen.ID,
			PenNumber:       pen.PenNumber,
			HouseID:         pen.HouseID,
			Capacity:        pen.Capacity,
			Status:          pen.Status,
			CurrentPigCount: currentPigCount,
		}

		if pen.PigBatchID != nil {
			penResponse.PigBatchID = pen.PigBatchID
		}
		response = append(response, penResponse)
	}

	return response, nil
}

func (s *pigFarmService) UpdatePen(ctx context.Context, id uint32, penNumber string, houseID uint32, capacity int, status models.PenStatus) (*dto.PenResponse, error) {
	serviceCtx := logs.AddFuncName(ctx, s.ctx, "UpdatePen")
	// 业务逻辑：验证所属猪舍是否存在
	_, err := s.farmRepository.GetPigHouseByID(serviceCtx, houseID)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, ErrHouseNotFound
		}
		return nil, err
	}

	pen := &models.Pen{
		Model:     models.Model{ID: id},
		PenNumber: penNumber,
		HouseID:   houseID,
		Capacity:  capacity,
		Status:    status,
	}
	rowsAffected, err := s.penRepository.UpdatePen(serviceCtx, pen)
	if err != nil {
		return nil, err
	}
	if rowsAffected == 0 {
		return nil, ErrPenNotFound
	}
	// 返回更新后的完整信息
	updatedPen, err := s.penRepository.GetPenByID(serviceCtx, id)
	if err != nil {
		return nil, err
	}
	return &dto.PenResponse{
		ID:         updatedPen.ID,
		PenNumber:  updatedPen.PenNumber,
		HouseID:    updatedPen.HouseID,
		Capacity:   updatedPen.Capacity,
		Status:     updatedPen.Status,
		PigBatchID: updatedPen.PigBatchID,
	}, nil
}

func (s *pigFarmService) DeletePen(ctx context.Context, id uint32) error {
	serviceCtx := logs.AddFuncName(ctx, s.ctx, "DeletePen")
	// 业务逻辑：检查猪栏是否被活跃批次使用
	pen, err := s.penRepository.GetPenByID(serviceCtx, id)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return ErrPenNotFound // 猪栏不存在
		}
		return err
	}

	// 检查猪栏是否关联了活跃批次
	// 注意：pen.PigBatchID 是指针类型，需要检查是否为 nil
	if pen.PigBatchID != nil && *pen.PigBatchID != 0 {
		pigBatch, err := s.batchRepository.GetPigBatchByID(serviceCtx, *pen.PigBatchID)
		if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
			return err
		}
		// 如果批次活跃，则不能删除猪栏
		if pigBatch != nil && pigBatch.IsActive() {
			return ErrPenInUse
		}
	}

	// 调用仓库层进行删除
	rowsAffected, err := s.penRepository.DeletePen(serviceCtx, id)
	if err != nil {
		return err
	}
	if rowsAffected == 0 {
		return ErrPenNotFound
	}
	return nil
}

// UpdatePenStatus 更新猪栏状态
func (s *pigFarmService) UpdatePenStatus(ctx context.Context, id uint32, newStatus models.PenStatus) (*dto.PenResponse, error) {
	serviceCtx, logger := logs.Trace(ctx, s.ctx, "UpdatePenStatus")
	var updatedPen *models.Pen
	err := s.uow.ExecuteInTransaction(serviceCtx, func(tx *gorm.DB) error {
		pen, err := s.penRepository.GetPenByIDTx(serviceCtx, tx, id)
		if err != nil {
			if errors.Is(err, gorm.ErrRecordNotFound) {
				return ErrPenNotFound
			}
			logger.Errorf("更新猪栏状态失败: 获取猪栏 %d 信息错误: %v", id, err)
			return fmt.Errorf("获取猪栏 %d 信息失败: %w", id, err)
		}

		// 业务逻辑：根据猪栏的 PigBatchID 和当前状态，判断是否允许设置为 newStatus
		if pen.PigBatchID != nil && *pen.PigBatchID != 0 { // 猪栏已被批次使用
			if newStatus == models.PenStatusEmpty { // 猪栏已被批次使用，不能直接设置为空闲
				return ErrPenStatusInvalidForOccupiedPen
			}
		} else { // 猪栏未被批次使用 (PigBatchID == nil)
			if newStatus == models.PenStatusOccupied { // 猪栏未被批次使用，不能设置为使用中
				return ErrPenStatusInvalidForUnoccupiedPen
			}
		}

		// 如果新状态与旧状态相同，则无需更新
		if pen.Status == newStatus {
			updatedPen = pen // 返回原始猪栏，因为没有实际更新
			return nil
		}

		updates := map[string]interface{}{
			"status": newStatus,
		}

		if err := s.penRepository.UpdatePenFieldsTx(serviceCtx, tx, id, updates); err != nil {
			logger.Errorf("更新猪栏 %d 状态失败: %v", id, err)
			return fmt.Errorf("更新猪栏 %d 状态失败: %w", id, err)
		}

		// 获取更新后的猪栏信息
		updatedPen, err = s.penRepository.GetPenByIDTx(serviceCtx, tx, id)
		if err != nil {
			logger.Errorf("更新猪栏状态后获取猪栏 %d 信息失败: %v", id, err)
			return fmt.Errorf("更新猪栏状态后获取猪栏 %d 信息失败: %w", id, err)
		}
		return nil
	})

	if err != nil {
		return nil, err
	}
	return &dto.PenResponse{
		ID:         updatedPen.ID,
		PenNumber:  updatedPen.PenNumber,
		HouseID:    updatedPen.HouseID,
		Capacity:   updatedPen.Capacity,
		Status:     updatedPen.Status,
		PigBatchID: updatedPen.PigBatchID,
	}, nil
}
