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/service/spu"
	"github.com/tidbcloud/tidb-management-service/utilities/bizerr"
)

func NewServer(
	storageSkuSvc spu.StorageMuService,
	instanceSkuSvc spu.InstanceMuService,
	skuSvc spu.SkuService,
	spuSvc spu.ServiceSpu,
) globaldedicatedv1.SpuServiceServer {
	return &server{
		storageSkuSvc:  storageSkuSvc,
		instanceSkuSvc: instanceSkuSvc,
		skuSvc:         skuSvc,
		spuSvc:         spuSvc,
	}
}

type server struct {
	storageSkuSvc  spu.StorageMuService
	instanceSkuSvc spu.InstanceMuService
	skuSvc         spu.SkuService
	spuSvc         spu.ServiceSpu
}

func (s *server) BuildDesiredComponents(
	ctx context.Context,
	request *globaldedicatedv1.BuildDesiredComponentsRequest,
) (*globaldedicatedv1.BuildDesiredComponentsResponse, error) {
	// TODO implement me
	panic("implement me")
}

func (s *server) GetInstanceMu(
	ctx context.Context,
	req *globaldedicatedv1.GetInstanceMuRequest,
) (*globaldedicatedv1.InstanceMu, error) {
	if req.Id == 0 {
		return nil, bizerr.New(bizerr.ErrCodeParams, "id is unspecified")
	}
	resp, err := s.instanceSkuSvc.Get(ctx, req)
	if err != nil {
		return nil, err
	}

	return resp, nil
}

func (s *server) ListInstanceMus(
	ctx context.Context,
	req *globaldedicatedv1.ListInstanceMusRequest,
) (*globaldedicatedv1.ListInstanceMusResponse, error) {
	resp, err := s.instanceSkuSvc.List(ctx, req)
	if err != nil {
		return nil, err
	}
	return resp, nil
}

func (s *server) BatchUpsertInstanceMus(
	ctx context.Context,
	req *globaldedicatedv1.BatchUpsertInstanceMusRequest,
) (*globaldedicatedv1.BatchUpsertInstanceMusResponse, error) {
	if len(req.GetAdds()) == 0 && len(req.GetDeletes()) == 0 {
		return nil, bizerr.New(bizerr.ErrCodeParams, "no adds, updates or deletes")
	}
	resp := &globaldedicatedv1.BatchUpsertInstanceMusResponse{}
	for _, instance := range req.GetAdds() {
		added, err := s.instanceSkuSvc.Create(ctx, instance)
		if err != nil {
			return resp, err
		}
		resp.Adds = append(resp.Adds, added)
	}
	for _, instance := range req.GetDeletes() {
		if err := s.instanceSkuSvc.Delete(ctx, instance); err != nil {
			return resp, err
		}
	}
	return resp, nil
}

func (s *server) GetStorageMu(
	ctx context.Context,
	req *globaldedicatedv1.GetStorageMuRequest,
) (*globaldedicatedv1.StorageMu, error) {
	if req.Id == 0 {
		return nil, bizerr.New(bizerr.ErrCodeParams, "id is unspecified")
	}
	resp, err := s.storageSkuSvc.Get(ctx, req)
	if err != nil {
		return nil, err
	}
	return resp, nil
}

func (s *server) ListStorageMus(
	ctx context.Context,
	req *globaldedicatedv1.ListStorageMusRequest,
) (*globaldedicatedv1.ListStorageMusResponse, error) {
	resp, err := s.storageSkuSvc.List(ctx, req)
	if err != nil {
		return nil, err
	}
	return resp, nil
}

func (s *server) BatchUpsertStorageMus(
	ctx context.Context,
	req *globaldedicatedv1.BatchUpsertStorageMusRequest,
) (*globaldedicatedv1.BatchUpsertStorageMusResponse, error) {
	if len(req.GetAdds()) == 0 && len(req.GetDeletes()) == 0 {
		return nil, bizerr.New(bizerr.ErrCodeParams, "no adds, updates or deletes")
	}
	resp := &globaldedicatedv1.BatchUpsertStorageMusResponse{}
	for _, storage := range req.GetAdds() {
		added, err := s.storageSkuSvc.Create(ctx, storage)
		if err != nil {
			return resp, err
		}
		resp.Adds = append(resp.Adds, added)
	}
	for _, storage := range req.GetDeletes() {
		if err := s.storageSkuSvc.Delete(ctx, storage); err != nil {
			return resp, err
		}
	}

	return resp, nil
}

func (s *server) GetSku(ctx context.Context, req *globaldedicatedv1.GetSkuRequest) (*globaldedicatedv1.Sku, error) {
	if req.Id == 0 {
		return nil, bizerr.New(bizerr.ErrCodeParams, "id is unspecified")
	}
	resp, err := s.skuSvc.GetSku(ctx, req)
	if err != nil {
		return nil, err
	}
	return resp, nil
}

func (s *server) ListSkus(
	ctx context.Context,
	req *globaldedicatedv1.ListSkusRequest,
) (*globaldedicatedv1.ListSkusResponse, error) {
	resp, err := s.skuSvc.ListSkus(ctx, req)
	if err != nil {
		return nil, err
	}
	return resp, nil
}

func (s *server) BatchUpsertSkus(
	ctx context.Context,
	req *globaldedicatedv1.BatchUpsertSkusRequest,
) (*globaldedicatedv1.BatchUpsertSkusResponse, error) {
	if len(req.GetAdds()) == 0 && len(req.GetUpdates()) == 0 && len(req.GetDeletes()) == 0 {
		return nil, bizerr.New(bizerr.ErrCodeParams, "no adds, updates or deletes")
	}
	resp := &globaldedicatedv1.BatchUpsertSkusResponse{}
	for _, sku := range req.GetAdds() {
		added, err := s.skuSvc.CreateSku(ctx, sku)
		if err != nil {
			return resp, err
		}
		resp.Adds = append(resp.Adds, added)
	}
	for _, update := range req.GetUpdates() {
		updated, err := s.skuSvc.UpdateSku(ctx, update)
		if err != nil {
			return resp, err
		}
		resp.Updates = append(resp.Updates, updated)
	}
	for _, sku := range req.GetDeletes() {
		if err := s.skuSvc.DeleteSku(ctx, sku); err != nil {
			return resp, err
		}
	}
	return resp, nil
}

func (s *server) GetSpu(ctx context.Context, req *globaldedicatedv1.GetSpuRequest) (*globaldedicatedv1.Spu, error) {
	resp, err := s.spuSvc.Get(ctx, req)
	if err != nil {
		return nil, err
	}
	return resp, nil
}

func (s *server) ListSpus(
	ctx context.Context,
	req *globaldedicatedv1.ListSpusRequest,
) (*globaldedicatedv1.ListSpusResponse, error) {
	spus, err := s.spuSvc.List(ctx, req)
	if err != nil {
		return nil, err
	}
	return &globaldedicatedv1.ListSpusResponse{
		Spus: spus,
	}, nil
}

func (s *server) BatchUpsertSpus(
	ctx context.Context,
	req *globaldedicatedv1.BatchUpsertSpusRequest,
) (*globaldedicatedv1.BatchUpsertSpusResponse, error) {
	if len(req.GetAdds()) == 0 && len(req.GetUpdates()) == 0 && len(req.GetDeletes()) == 0 {
		return nil, bizerr.New(bizerr.ErrCodeParams, "no adds, updates or deletes")
	}
	resp := &globaldedicatedv1.BatchUpsertSpusResponse{}
	for _, it := range req.GetAdds() {
		added, err := s.spuSvc.Create(ctx, it)
		if err != nil {
			return resp, err
		}
		resp.Adds = append(resp.Adds, added)
	}
	for _, update := range req.GetUpdates() {
		updated, err := s.spuSvc.Update(ctx, update)
		if err != nil {
			return resp, err
		}
		resp.Updates = append(resp.Updates, updated)
	}
	for _, it := range req.GetDeletes() {
		if err := s.spuSvc.Delete(ctx, it); err != nil {
			return resp, err
		}
	}
	return resp, nil
}
