package backend

import (
	"context"
	"time"

	"github.com/tidbcloud/chaos-svc/idl/pbgen/proto/chaos"
	"github.com/tidbcloud/chaos-svc/pkg/domain/constant"
	"github.com/tidbcloud/chaos-svc/pkg/domain/entity"
	"github.com/tidbcloud/chaos-svc/pkg/domain/facade"
	"github.com/tidbcloud/chaos-svc/pkg/domain/repo"
	"github.com/tidbcloud/chaos-svc/pkg/domain/vo"
	cloudv1alpha1 "github.com/tidbcloud/eks-provider/api/v1alpha1"
	"github.com/tidbcloud/pkgv2/bizerr"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

type EnableBackendSvc interface {
	Execute(ctx context.Context, params *EnableBackendParam) bizerr.BizError
}

type EnableBackendParam struct {
	ProjectID    uint64
	NetworkName  string
	Region       string
	ProviderType string
	UserID       uint64
}

type enableBackendImp struct {
	backendRepo repo.BackendRepo
	infraFacade facade.Infra
}

func NewEnableBackendSvc(
	backendRepo repo.BackendRepo,
	infraFacade facade.Infra,
) EnableBackendSvc {
	return &enableBackendImp{
		backendRepo: backendRepo,
		infraFacade: infraFacade,
	}
}

func (imp *enableBackendImp) Execute(ctx context.Context, params *EnableBackendParam) bizerr.BizError {
	var backendEntity *entity.Backend
	backendEntity, err := imp.backendRepo.Load(ctx, params.ProjectID, params.NetworkName)
	if err != nil {
		backendEntity, err = buildBackendEntity(params)
		if err != nil {
			return err
		}
	}

	if err := backendEntity.StartEnable(params.UserID); err != nil {
		return err
	}
	chaosServerCR := imp.buildChaosServerCR(params)
	if err := imp.infraFacade.CreateChaosServerIgnoreExist(ctx, chaosServerCR); err != nil {
		return err
	}
	if err := imp.backendRepo.Save(ctx, backendEntity); err != nil {
		return err
	}
	return nil
}

func buildBackendEntity(params *EnableBackendParam) (*entity.Backend, bizerr.BizError) {
	backendEntity := &entity.Backend{
		ProjectID:      params.ProjectID,
		NetworkName:    params.NetworkName,
		Status:         chaos.ChaosBackendStatus_CHAOS_BACKEND_STATUS_DISABLED,
		Message:        "",
		Type2Operation: map[constant.ChaosBackendOperationType]*vo.BackendOperation{},
		CreatedAt:      time.Time{},
		Versioning:     0,
	}
	return backendEntity, nil
}

func (imp *enableBackendImp) buildChaosServerCR(params *EnableBackendParam) *cloudv1alpha1.ChaosServer {
	return &cloudv1alpha1.ChaosServer{
		ObjectMeta: metav1.ObjectMeta{
			Namespace: imp.infraFacade.Namespace(params.ProjectID),
			Name:      imp.infraFacade.ChaosServerName(params.ProjectID, params.NetworkName),
			Labels: map[string]string{
				facade.LabelKeyRegion:       params.Region,
				facade.LabelKeyProviderType: params.ProviderType,
			},
		},
		Spec: cloudv1alpha1.ChaosServerSpec{
			NetworkName: params.NetworkName,
		},
	}
}
