package cvt

import (
	"fmt"

	"github.com/tidbcloud/chaos-svc/idl/pbgen/proto/chaos"
	"github.com/tidbcloud/chaos-svc/model"
	"github.com/tidbcloud/chaos-svc/pkg/domain/constant"
	"github.com/tidbcloud/chaos-svc/pkg/domain/entity"
	"github.com/tidbcloud/chaos-svc/pkg/domain/vo"
)

type BackendGroup struct {
	Backend        *model.ChaosBackend
	Type2Operation map[constant.ChaosBackendOperationType]*model.ChaosBackendOperation
}

func BackendEntity2Model(backendEntity *entity.Backend) *BackendGroup {
	backendModel := &model.ChaosBackend{
		ProjectID:   model.ID(backendEntity.ProjectID),
		NetworkName: backendEntity.NetworkName,
		Status:      BackendStatusPb2Model(backendEntity.Status),
		Message:     backendEntity.Message,
		CreatedAt:   backendEntity.CreatedAt,
		Versioned:   model.Versioned{Versioning: backendEntity.Versioning},
	}

	type2Operation := make(map[constant.ChaosBackendOperationType]*model.ChaosBackendOperation)
	for _, operation := range backendEntity.Type2Operation {
		type2Operation[operation.Type] = &model.ChaosBackendOperation{
			Updatable:   model.Updatable{Base: model.Base{ID: model.ID(operation.ID)}},
			ProjectID:   model.ID(backendEntity.ProjectID),
			NetworkName: backendEntity.NetworkName,
			// ChaosBackend: nil,
			Type:        model.ChaosBackendOperationType(operation.Type),
			Status:      model.ChaosBackendOperationStatus(operation.Status),
			CreatedByID: model.ID(operation.CreatedByID),
			CompletedAt: operation.CompletedAt,
		}
	}
	return &BackendGroup{
		Backend:        backendModel,
		Type2Operation: type2Operation,
	}
}

func BackendModel2Entity(
	backendModel *model.ChaosBackend,
	type2OperationModel map[constant.ChaosBackendOperationType]*model.ChaosBackendOperation,
) *entity.Backend {
	type2Operation := make(map[constant.ChaosBackendOperationType]*vo.BackendOperation)
	for _, operation := range type2OperationModel {
		type2Operation[constant.ChaosBackendOperationType(operation.Type)] = &vo.BackendOperation{
			ID:          operation.ID.Uint64(),
			Type:        constant.ChaosBackendOperationType(operation.Type),
			Status:      constant.ChaosBackendOperationStatus(operation.Status),
			CreatedAt:   operation.CreatedAt,
			CreatedByID: operation.CreatedByID.Uint64(),
			CompletedAt: operation.CompletedAt,
		}
	}
	return &entity.Backend{
		ProjectID:      backendModel.ProjectID.Uint64(),
		NetworkName:    backendModel.NetworkName,
		Status:         BackendStatusModel2Pb(backendModel.Status),
		Message:        backendModel.Message,
		Type2Operation: type2Operation,
		CreatedAt:      backendModel.CreatedAt,
		Versioning:     backendModel.Versioning,
	}
}

func BackendStatusPb2Model(status chaos.ChaosBackendStatus) model.ChaosBackendStatus {
	switch status {
	case chaos.ChaosBackendStatus_CHAOS_BACKEND_STATUS_READY:
		return model.ChaosBackendStatusReady
	case chaos.ChaosBackendStatus_CHAOS_BACKEND_STATUS_DISABLED:
		return model.ChaosBackendStatusDisabled
	case chaos.ChaosBackendStatus_CHAOS_BACKEND_STATUS_INSTALLING:
		return model.ChaosBackendStatusInstalling
	case chaos.ChaosBackendStatus_CHAOS_BACKEND_STATUS_INSTALL_FAILED:
		return model.ChaosBackendStatusInstallFailed
	case chaos.ChaosBackendStatus_CHAOS_BACKEND_STATUS_UNINSTALLING:
		return model.ChaosBackendStatusUninstalling
	}
	panic(fmt.Sprintf("invalid backend status: %s", status))
}

func BackendStatusModel2Pb(status model.ChaosBackendStatus) chaos.ChaosBackendStatus {
	switch status {
	case model.ChaosBackendStatusReady:
		return chaos.ChaosBackendStatus_CHAOS_BACKEND_STATUS_READY
	case model.ChaosBackendStatusDisabled:
		return chaos.ChaosBackendStatus_CHAOS_BACKEND_STATUS_DISABLED
	case model.ChaosBackendStatusInstalling:
		return chaos.ChaosBackendStatus_CHAOS_BACKEND_STATUS_INSTALLING
	case model.ChaosBackendStatusInstallFailed:
		return chaos.ChaosBackendStatus_CHAOS_BACKEND_STATUS_INSTALL_FAILED
	case model.ChaosBackendStatusUninstalling:
		return chaos.ChaosBackendStatus_CHAOS_BACKEND_STATUS_UNINSTALLING
	}
	panic(fmt.Sprintf("invalid backend status: %s", status))
}
