package spu

import (
	"context"

	globaldedicatedv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/dedicated/v1"
	"github.com/tidbcloud/tidb-management-service/dedicated-global-service/domain/entity"
	"github.com/tidbcloud/tidb-management-service/dedicated-global-service/domain/repository/spu"
	"github.com/tidbcloud/tidb-management-service/utilities/bizerr"
)

//go:generate go run go.uber.org/mock/mockgen@latest -source=$GOFILE -package=mock_$GOPACKAGE -destination=./mock_$GOPACKAGE/mock_$GOFILE
type StorageMuService interface {
	Get(ctx context.Context, req *globaldedicatedv1.GetStorageMuRequest) (*entity.StorageMu, bizerr.BizError)
	List(
		ctx context.Context,
		req *globaldedicatedv1.ListStorageMusRequest,
	) (*globaldedicatedv1.ListStorageMusResponse, bizerr.BizError)
	Delete(ctx context.Context, id uint64) bizerr.BizError
	Create(ctx context.Context, req *globaldedicatedv1.StorageMu) (*entity.StorageMu, bizerr.BizError)
	Update(ctx context.Context, req *globaldedicatedv1.StorageMu) (*entity.StorageMu, bizerr.BizError)
}

type storageMuServiceImpl struct {
	storageMuRepo spu.StorageMuRepo
}

func NewStorageMuService(storageMuRep spu.StorageMuRepo) StorageMuService {
	return &storageMuServiceImpl{
		storageMuRepo: storageMuRep,
	}
}

func (s *storageMuServiceImpl) Get(
	ctx context.Context,
	req *globaldedicatedv1.GetStorageMuRequest,
) (*entity.StorageMu, bizerr.BizError) {
	ctx, span := tracer.Start(ctx, "Domain.GetStorageSku")
	defer span.End()

	return s.storageMuRepo.Get(ctx, req.GetId())
}

func (s *storageMuServiceImpl) List(
	ctx context.Context,
	req *globaldedicatedv1.ListStorageMusRequest,
) (*globaldedicatedv1.ListStorageMusResponse, bizerr.BizError) {
	ctx, span := tracer.Start(ctx, "Domain.ListStorageSkus")
	defer span.End()

	sts, err := s.storageMuRepo.List(ctx, spu.StorageMuFilter{
		Provider:    req.GetCloudProvider(),
		VolumeTypes: req.GetVolumeTypes(),
	})
	if err != nil {
		return nil, err
	}
	return &globaldedicatedv1.ListStorageMusResponse{
		StorageMus: sts,
	}, nil
}

func (s *storageMuServiceImpl) Delete(ctx context.Context, id uint64) bizerr.BizError {
	ctx, span := tracer.Start(ctx, "Domain.DeleteStorageSku")
	defer span.End()

	return s.storageMuRepo.Delete(ctx, id)
}

func (s *storageMuServiceImpl) Create(
	ctx context.Context,
	req *globaldedicatedv1.StorageMu,
) (*entity.StorageMu, bizerr.BizError) {
	ctx, span := tracer.Start(ctx, "Donmain.CreateStorageSku")
	defer span.End()

	id, err := s.storageMuRepo.Save(ctx, req)
	if err != nil {
		return nil, err
	}
	req.Id = uint64(id)
	return req, nil
}

func (s *storageMuServiceImpl) Update(
	ctx context.Context,
	req *globaldedicatedv1.StorageMu,
) (*entity.StorageMu, bizerr.BizError) {
	ctx, span := tracer.Start(ctx, "Domain.UpdateStorageSku")
	defer span.End()

	existing, err := s.storageMuRepo.Get(ctx, req.GetId())
	if err != nil {
		return nil, err
	}
	if req.GetVolumeType() != globaldedicatedv1.StorageMu_VOLUME_TYPE_UNSPECIFIED {
		existing.VolumeType = req.GetVolumeType()
	}
	if _, err := s.storageMuRepo.Save(ctx, existing); err != nil {
		return nil, err
	}
	return existing, nil
}
