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 InstanceMuService interface {
	Get(ctx context.Context, req *globaldedicatedv1.GetInstanceMuRequest) (*entity.InstanceMu, bizerr.BizError)
	List(
		ctx context.Context,
		req *globaldedicatedv1.ListInstanceMusRequest,
	) (*globaldedicatedv1.ListInstanceMusResponse, bizerr.BizError)
	Delete(ctx context.Context, id uint64) bizerr.BizError
	Create(ctx context.Context, req *globaldedicatedv1.InstanceMu) (*entity.InstanceMu, bizerr.BizError)
	Update(ctx context.Context, req *globaldedicatedv1.InstanceMu) (*entity.InstanceMu, bizerr.BizError)
}

type instanceMuServiceImpl struct {
	instanceMuRepo spu.InstanceMuRepo
}

func NewInstanceMuService(instanceMuRepo spu.InstanceMuRepo) InstanceMuService {
	return &instanceMuServiceImpl{
		instanceMuRepo: instanceMuRepo,
	}
}

func (s *instanceMuServiceImpl) Get(
	ctx context.Context,
	req *globaldedicatedv1.GetInstanceMuRequest,
) (*entity.InstanceMu, bizerr.BizError) {
	ctx, span := tracer.Start(ctx, "Domain.GetInstanceSku")
	defer span.End()

	return s.instanceMuRepo.GetByID(ctx, req.GetId())
}

func (s *instanceMuServiceImpl) List(
	ctx context.Context,
	req *globaldedicatedv1.ListInstanceMusRequest,
) (*globaldedicatedv1.ListInstanceMusResponse, bizerr.BizError) {
	ctx, span := tracer.Start(ctx, "Domain.ListInstanceSkus")
	defer span.End()

	its, err := s.instanceMuRepo.Query(ctx, spu.InstanceMuFilter{
		Provider: req.GetCloudProvider(),
		CpuArchs: req.GetCpuArchs(),
	})
	if err != nil {
		return nil, err
	}

	return &globaldedicatedv1.ListInstanceMusResponse{
		InstanceMus: its,
	}, nil
}

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

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

func (s *instanceMuServiceImpl) Create(
	ctx context.Context,
	req *globaldedicatedv1.InstanceMu,
) (*entity.InstanceMu, bizerr.BizError) {
	ctx, span := tracer.Start(ctx, "Domain.CreateInstanceSku")
	defer span.End()

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

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

	existing, err := s.instanceMuRepo.GetByID(ctx, req.GetId())
	if err != nil {
		return nil, err
	}
	if req.GetInstanceType() != "" {
		existing.InstanceType = req.GetInstanceType()
	}
	if req.GetCpuCore() != 0 {
		existing.CpuCore = req.GetCpuCore()
	}
	if req.GetMemoryGi() != 0 {
		existing.MemoryGi = req.GetMemoryGi()
	}
	if req.GetCpuArch() != globaldedicatedv1.InstanceMu_CPU_ARCH_UNSPECIFIED {
		existing.CpuArch = req.GetCpuArch()
	}
	if _, err := s.instanceMuRepo.Save(ctx, existing); err != nil {
		return nil, err
	}

	return existing, nil
}
