package spu

import (
	"context"

	"google.golang.org/protobuf/types/known/emptypb"

	globaldedicatedv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/dedicated/v1"
	tidbmgmtservicev1 "github.com/tidbcloud/tidb-management-service/api/spec/tidb_mgmt_service/v1"
	"github.com/tidbcloud/tidb-management-service/utilities/bizerr"
)

func (s *serverImpl) CreateStorageMu(
	ctx context.Context,
	req *tidbmgmtservicev1.CreateStorageMuRequest,
) (*tidbmgmtservicev1.StorageMu, error) {
	ctx, span := tracer.Start(ctx, "CreateStorageMu")
	defer span.End()

	if req.GetStorageMu() == nil {
		return nil, bizerr.New(bizerr.ErrCodeParams, "StorageMu is required")
	}
	smu := req.GetStorageMu()
	outputs, err := s.dedicatedCli.BatchUpsertStorageMus(ctx, &globaldedicatedv1.BatchUpsertStorageMusRequest{
		Adds: []*globaldedicatedv1.StorageMu{covertStorageMuToGlobal(smu)},
	})
	if err != nil {
		return nil, err
	}
	if len(outputs.GetAdds()) != 1 {
		return nil, bizerr.New(bizerr.ErrCodeGRPC, "unexpected storage mu added")
	}
	return covertStorageMuToMgmt(outputs.GetAdds()[0]), nil
}

func (s *serverImpl) DeleteStorageMu(
	ctx context.Context,
	req *tidbmgmtservicev1.DeleteStorageMuRequest,
) (*emptypb.Empty, error) {
	ctx, span := tracer.Start(ctx, "DeleteStorageMu")
	defer span.End()

	if req.GetId() == 0 {
		return nil, bizerr.New(bizerr.ErrCodeParams, "StorageMuId is required")
	}
	_, err := s.dedicatedCli.BatchUpsertStorageMus(ctx, &globaldedicatedv1.BatchUpsertStorageMusRequest{
		Deletes: []uint64{req.GetId()},
	})
	if err != nil {
		return nil, err
	}
	return &emptypb.Empty{}, nil
}

func (s *serverImpl) GetStorageMu(
	ctx context.Context,
	req *tidbmgmtservicev1.GetStorageMuRequest,
) (*tidbmgmtservicev1.StorageMu, error) {
	ctx, span := tracer.Start(ctx, "GetStorageMu")
	defer span.End()

	if req.GetId() == 0 {
		return nil, bizerr.New(bizerr.ErrCodeParams, "StorageMuId is required")
	}
	output, err := s.dedicatedCli.GetStorageMu(ctx, &globaldedicatedv1.GetStorageMuRequest{
		Id: req.GetId(),
	})
	if err != nil {
		return nil, err
	}
	return covertStorageMuToMgmt(output), nil
}

func (s *serverImpl) ListStorageMus(
	ctx context.Context,
	req *tidbmgmtservicev1.ListStorageMusRequest,
) (*tidbmgmtservicev1.ListStorageMusResponse, error) {
	ctx, span := tracer.Start(ctx, "ListStorageMus")
	defer span.End()

	outputs, err := s.dedicatedCli.ListStorageMus(ctx, &globaldedicatedv1.ListStorageMusRequest{
		CloudProvider: req.GetCloudProvider(),
		VolumeTypes:   req.GetVolumeTypes(),
	})
	if err != nil {
		return nil, err
	}

	storageMus := make([]*tidbmgmtservicev1.StorageMu, 0, len(outputs.StorageMus))
	for _, sku := range outputs.GetStorageMus() {
		storageMus = append(storageMus, covertStorageMuToMgmt(sku))
	}

	return &tidbmgmtservicev1.ListStorageMusResponse{
		StorageMus: storageMus,
	}, nil
}

func covertStorageMuToGlobal(smu *tidbmgmtservicev1.StorageMu) *globaldedicatedv1.StorageMu {
	return &globaldedicatedv1.StorageMu{
		Id:            smu.GetId(),
		CloudProvider: smu.GetCloudProvider(),
		VolumeType:    smu.GetVolumeType(),
	}
}

func covertStorageMuToMgmt(sku *globaldedicatedv1.StorageMu) *tidbmgmtservicev1.StorageMu {
	return &tidbmgmtservicev1.StorageMu{
		Id:            sku.GetId(),
		CloudProvider: sku.GetCloudProvider(),
		VolumeType:    sku.GetVolumeType(),
	}
}
