package backend

import (
	"context"

	"github.com/tidbcloud/chaos-svc/idl/pbgen/proto/chaos"
	"github.com/tidbcloud/chaos-svc/pkg/domain/constant"
	"github.com/tidbcloud/chaos-svc/pkg/domain/facade"
	"github.com/tidbcloud/chaos-svc/pkg/domain/repo"
	"github.com/tidbcloud/chaos-svc/pkg/domain/vo"
	"github.com/tidbcloud/pkgv2/bizerr"
)

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

func NewGetBackendSvc(backendRepo repo.BackendRepo, infraFacade facade.Infra) *GetBackendSvc {
	return &GetBackendSvc{
		backendRepo: backendRepo,
		infraFacade: infraFacade,
	}
}

type Backend struct {
	Status      chaos.ChaosBackendStatus
	Message     string
	UpdatedAt   int64
	UpdatedByID uint64
}

func (svc *GetBackendSvc) Execute(ctx context.Context, req *chaos.GetChaosBackendRequest) (*Backend, bizerr.BizError) {
	tidbCluster, err := svc.infraFacade.GetTiDBCluster(ctx, req.ProjectId, req.ClusterId)
	if err != nil {
		// if cluster is deleted, return `disabled` as result
		return handleRecordNotFoundError(err)
	}

	backendEntity, err := svc.backendRepo.Load(ctx, req.ProjectId, tidbCluster.NetworkName)
	if err != nil {
		// if backend record is not found, return `disabled` as result
		return handleRecordNotFoundError(err)
	}

	var op *vo.BackendOperation
	var ok bool
	if op, ok = backendEntity.Type2Operation[constant.ChaosBackendOperationTypeEnable]; !ok {
		op, ok = backendEntity.Type2Operation[constant.ChaosBackendOperationTypeDisable]
		if !ok {
			return nil, bizerr.New(bizerr.ErrCodeRecordNotFound, "operation not found")
		}
	}

	return &Backend{
		Status:      backendEntity.Status,
		Message:     backendEntity.Message,
		UpdatedAt:   op.CreatedAt.Unix(),
		UpdatedByID: op.CreatedByID,
	}, nil
}

func handleRecordNotFoundError(err bizerr.BizError) (*Backend, bizerr.BizError) {
	if err.ErrCode() == bizerr.ErrCodeRecordNotFound {
		return &Backend{
			Status: chaos.ChaosBackendStatus_CHAOS_BACKEND_STATUS_DISABLED,
		}, nil
	}
	return nil, err
}
