package service

import (
	"context"
	"errors"
	"fmt"

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

// 定义营养种类服务特定的错误
var (
	ErrNutrientNameConflict = errors.New("营养种类名称已存在")
	ErrNutrientNotFound     = errors.New("营养种类不存在")
)

// NutrientService 定义了营养种类相关的应用服务接口
type NutrientService interface {
	CreateNutrient(ctx context.Context, req *dto.CreateNutrientRequest) (*dto.NutrientResponse, error)
	UpdateNutrient(ctx context.Context, id uint32, req *dto.UpdateNutrientRequest) (*dto.NutrientResponse, error)
	DeleteNutrient(ctx context.Context, id uint32) error
	GetNutrient(ctx context.Context, id uint32) (*dto.NutrientResponse, error)
	ListNutrients(ctx context.Context, req *dto.ListNutrientRequest) (*dto.ListNutrientResponse, error)
}

// nutrientServiceImpl 是 NutrientService 接口的实现
type nutrientServiceImpl struct {
	ctx       context.Context
	recipeSvc recipe.Service
}

// NewNutrientService 创建一个新的 NutrientService 实例
func NewNutrientService(ctx context.Context, recipeSvc recipe.Service) NutrientService {
	return &nutrientServiceImpl{
		ctx:       ctx,
		recipeSvc: recipeSvc,
	}
}

// CreateNutrient 创建营养种类
func (s *nutrientServiceImpl) CreateNutrient(ctx context.Context, req *dto.CreateNutrientRequest) (*dto.NutrientResponse, error) {
	serviceCtx := logs.AddFuncName(ctx, s.ctx, "CreateNutrient")

	nutrient, err := s.recipeSvc.CreateNutrient(serviceCtx, req.Name, req.Description)
	if err != nil {
		if errors.Is(err, recipe.ErrNutrientNameConflict) {
			return nil, ErrNutrientNameConflict
		}
		return nil, fmt.Errorf("创建营养种类失败: %w", err)
	}
	return dto.ConvertNutrientToDTO(nutrient), nil
}

// UpdateNutrient 更新营养种类
func (s *nutrientServiceImpl) UpdateNutrient(ctx context.Context, id uint32, req *dto.UpdateNutrientRequest) (*dto.NutrientResponse, error) {
	serviceCtx := logs.AddFuncName(ctx, s.ctx, "UpdateNutrient")

	nutrient, err := s.recipeSvc.UpdateNutrient(serviceCtx, id, req.Name, req.Description)
	if err != nil {
		if errors.Is(err, recipe.ErrNutrientNotFound) {
			return nil, ErrNutrientNotFound
		}
		if errors.Is(err, recipe.ErrNutrientNameConflict) {
			return nil, ErrNutrientNameConflict
		}
		return nil, fmt.Errorf("更新营养种类失败: %w", err)
	}
	return dto.ConvertNutrientToDTO(nutrient), nil
}

// DeleteNutrient 删除营养种类
func (s *nutrientServiceImpl) DeleteNutrient(ctx context.Context, id uint32) error {
	serviceCtx := logs.AddFuncName(ctx, s.ctx, "DeleteNutrient")
	err := s.recipeSvc.DeleteNutrient(serviceCtx, id)
	if err != nil {
		if errors.Is(err, recipe.ErrNutrientNotFound) {
			return ErrNutrientNotFound
		}
		return fmt.Errorf("删除营养种类失败: %w", err)
	}
	return nil
}

// GetNutrient 获取单个营养种类
func (s *nutrientServiceImpl) GetNutrient(ctx context.Context, id uint32) (*dto.NutrientResponse, error) {
	serviceCtx := logs.AddFuncName(ctx, s.ctx, "GetNutrient")

	nutrient, err := s.recipeSvc.GetNutrient(serviceCtx, id)
	if err != nil {
		if errors.Is(err, recipe.ErrNutrientNotFound) {
			return nil, ErrNutrientNotFound
		}
		return nil, fmt.Errorf("获取营养种类失败: %w", err)
	}
	return dto.ConvertNutrientToDTO(nutrient), nil
}

// ListNutrients 列出营养种类
func (s *nutrientServiceImpl) ListNutrients(ctx context.Context, req *dto.ListNutrientRequest) (*dto.ListNutrientResponse, error) {
	serviceCtx := logs.AddFuncName(ctx, s.ctx, "ListNutrients")

	opts := repository.NutrientListOptions{
		Name:            req.Name,
		RawMaterialName: req.RawMaterialName,
		OrderBy:         req.OrderBy,
	}
	nutrients, total, err := s.recipeSvc.ListNutrients(serviceCtx, opts, req.Page, req.PageSize)
	if err != nil {
		return nil, fmt.Errorf("获取营养种类列表失败: %w", err)
	}

	return dto.ConvertNutrientListToDTO(nutrients, total, req.Page, req.PageSize), nil
}
