package cvt

import (
	globalcommonv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/common/v1"
	"github.com/tidbcloud/tidb-management-service/serverless-global-service/domain/entity"
	"github.com/tidbcloud/tidb-management-service/serverless-global-service/infra/persistence/model"
	"github.com/tidbcloud/tidb-management-service/utilities/bizerr"
	"github.com/tidbcloud/tidb-management-service/utilities/enum"
)

const defaultRegionEngineType = globalcommonv1.Region_MYSQL_COMPATIBLE

func CloudProviderModelStatus2EnStatus(status string) globalcommonv1.CloudProvider_State {
	switch status {
	case model.ProviderStatusActive:
		return globalcommonv1.CloudProvider_ACTIVE
	case model.ProviderStatusInactive:
		return globalcommonv1.CloudProvider_INACTIVE
	}
	return globalcommonv1.CloudProvider_STATE_UNSPECIFIED
}

func CloudProviderEnStatusToModelStatus(status globalcommonv1.CloudProvider_State) string {
	switch status {
	case globalcommonv1.CloudProvider_ACTIVE:
		return model.ProviderStatusActive
	case globalcommonv1.CloudProvider_INACTIVE:
		return model.ProviderStatusInactive
	}
	return "unknown"
}

func RegionModelStatus2EnStatus(status string) globalcommonv1.Region_State {
	switch status {
	case model.RegionStatusActive:
		return globalcommonv1.Region_ACTIVE
	case model.RegionStatusInactive:
		return globalcommonv1.Region_INACTIVE
	}

	return globalcommonv1.Region_STATE_UNSPECIFIED
}

func RegionEnStatusToModelStatus(status globalcommonv1.Region_State) string {
	switch status {
	case globalcommonv1.Region_ACTIVE:
		return model.RegionStatusActive
	case globalcommonv1.Region_INACTIVE:
		return model.RegionStatusInactive
	}

	return "unknown"
}

func RegionModel2Entity(regionModel *model.Region, providerModel *model.Provider) (*entity.Region, error) {
	// fill CloudProviderId
	cloudProviderName, err := enum.FromString[globalcommonv1.CloudProvider_Name](providerModel.Name)
	if err != nil {
		return nil, bizerr.New(bizerr.ErrCodeUnknown, "cloud provider %s is not supported", providerModel.Name)
	}

	regionId, err := enum.RegionFromString(providerModel.Name, regionModel.Name)
	if err != nil || regionId == globalcommonv1.Region_NAME_UNSPECIFIED {
		return nil, bizerr.WrapErrorWithCode(err, bizerr.ErrCodeParams, "invalid region: %s", regionModel.Name)
	}
	region := &entity.Region{
		Id:                regionId,
		CloudProviderId:   globalcommonv1.CloudProvider_Name(cloudProviderName),
		DisplayName:       regionModel.DisplayName,
		LogicalName:       regionModel.Name,
		ServiceAddress:    regionModel.ServiceAddress,
		IsPublic:          regionModel.IsPublic,
		State:             RegionModelStatus2EnStatus(regionModel.Status),
		DefaultBackupTime: regionModel.DefaultBackupTime,
		OpenedTenantIds:   []uint64{},
		ServicePlan:       globalcommonv1.ServicePlan(globalcommonv1.ServicePlan_value[regionModel.ServicePlan]),
		EngineType:        defaultRegionEngineType,
		Sys9Config: &globalcommonv1.RegionSys9Config{
			OemProfileRef:           regionModel.Sys9Config.OemProfileRef,
			AuthMode:                regionModel.Sys9Config.AuthMode,
			TokenTtlSec:             regionModel.Sys9Config.TokenTtlSec,
			SessionRefreshBeforeSec: regionModel.Sys9Config.SessionRefreshBeforeSec,
			RetryPolicyRef:          regionModel.Sys9Config.RetryPolicyRef,
		},
	}
	if regionModel.EngineType != "" {
		engineType, err := enum.FromString[globalcommonv1.Region_EngineType](regionModel.EngineType)
		if err != nil {
			return nil, bizerr.WrapErrorWithCode(err, bizerr.ErrCodeParams, "invalid region engine type: %s", regionModel.EngineType)
		}
		region.EngineType = globalcommonv1.Region_EngineType(engineType)
	}

	for _, r := range regionModel.RegionTenants {
		region.OpenedTenantIds = append(region.OpenedTenantIds, r.TenantId)
	}
	return region, nil
}

func CloudProvider2En(providerModel *model.Provider) (*entity.CloudProvider, error) {
	// fill CloudProviderId
	cloudProviderName, err := enum.FromString[globalcommonv1.CloudProvider_Name](providerModel.Name)
	if err != nil {
		return nil, bizerr.New(bizerr.ErrCodeUnknown, "cloud provider %s is not supported", providerModel.Name)
	}

	out := &entity.CloudProvider{
		Id:          globalcommonv1.CloudProvider_Name(cloudProviderName),
		DisplayName: providerModel.Name,
		IsPublic:    providerModel.IsPublic,
		State:       CloudProviderModelStatus2EnStatus(providerModel.Status),
	}

	for _, region := range providerModel.Regions {
		r, err := RegionModel2Entity(region, providerModel)
		if err != nil {
			return nil, err
		}
		out.Regions = append(out.Regions, r)
	}

	return out, nil
}

func CloudProviderEnToModel(en *entity.CloudProvider) *model.Provider {
	p := &model.Provider{
		Name:     en.Id.String(),
		IsPublic: en.IsPublic,
		Status:   CloudProviderEnStatusToModelStatus(en.State),
	}

	if en.Id > 0 {
		p.ID = uint(en.Id)
	}

	return p
}

func RegionEnToModel(en *entity.Region) *model.Region {
	p := &model.Region{
		Name:              en.Id.String(),
		DisplayName:       en.DisplayName,
		IsPublic:          en.IsPublic,
		Status:            RegionEnStatusToModelStatus(en.State),
		ServiceAddress:    en.ServiceAddress,
		DefaultBackupTime: en.GetDefaultBackupTime(),
		ServicePlan:       en.GetServicePlan().String(),
		EngineType:        en.GetEngineType().String(),
	}
	if p.EngineType == globalcommonv1.Region_ENGINE_TYPE_UNSPECIFIED.String() {
		p.EngineType = defaultRegionEngineType.String()
	}
	if en.GetSys9Config() != nil {
		p.Sys9Config = model.RegionSys9Config{
			OemProfileRef:           en.GetSys9Config().GetOemProfileRef(),
			AuthMode:                en.GetSys9Config().GetAuthMode(),
			TokenTtlSec:             en.GetSys9Config().GetTokenTtlSec(),
			SessionRefreshBeforeSec: en.GetSys9Config().GetSessionRefreshBeforeSec(),
			RetryPolicyRef:          en.GetSys9Config().GetRetryPolicyRef(),
		}
	}

	return p
}
