package jump

import (
	"strconv"
)

type (
	// DestinationType is the type of destination.
	DestinationType string
)

const (
	DestinationTypeUnspecified         DestinationType = "unspecified"
	DestinationTypeControlPlane        DestinationType = "controlplane"
	DestinationTypeDedicated           DestinationType = "dedicated"
	DestinationTypeServerless          DestinationType = "serverless"
	DestinationTypeByoc                DestinationType = "byoc"
	DestinationTypePremium             DestinationType = "premium"
	DestinationTypePremiumResourcePool DestinationType = "premium_resource_pool"

	// Some built-in cluster names.
	ControlPlaneInfraAPIServer string = "infra-apiserver"
)

var (
	DestinationTypeValues = []DestinationType{
		DestinationTypeControlPlane,
		DestinationTypeDedicated,
		DestinationTypeServerless,
		DestinationTypeByoc,
		DestinationTypePremium,
		DestinationTypePremiumResourcePool,
	}
)

type IDestination interface {
	Type() DestinationType
	ID() string
	IsDataplane() bool
}

type DestinationUnspecified struct{}

func (d *DestinationUnspecified) Type() DestinationType { return DestinationTypeUnspecified }

func (d *DestinationUnspecified) ID() string { return "unspecified" }

func (d *DestinationUnspecified) IsDataplane() bool { return false }

type DestinationControlPlane struct {
	Name string `json:"name,omitempty"`
}

func AsDestinationControlPlane(dest IDestination) (*DestinationControlPlane, bool) {
	d, ok := dest.(*DestinationControlPlane)
	return d, ok
}

func (d *DestinationControlPlane) Type() DestinationType { return DestinationTypeControlPlane }

func (d *DestinationControlPlane) ID() string { return d.Name }

func (d *DestinationControlPlane) IsDataplane() bool {
	return false
}

type DestinationServerlessCluster struct {
	Name string `json:"name,omitempty"`
}

func AsDestinationServerlessCluster(dest IDestination) (*DestinationServerlessCluster, bool) {
	d, ok := dest.(*DestinationServerlessCluster)
	return d, ok
}

func (d *DestinationServerlessCluster) Type() DestinationType { return DestinationTypeServerless }

func (d *DestinationServerlessCluster) ID() string { return d.Name }

func (d *DestinationServerlessCluster) IsDataplane() bool {
	return false
}

type DestinationDedicatedCluster struct {
	ClusterID uint64 `json:"cluster_id,string,omitempty"`
}

func AsDestinationDedicatedCluster(dest IDestination) (*DestinationDedicatedCluster, bool) {
	d, ok := dest.(*DestinationDedicatedCluster)
	return d, ok
}

func (d *DestinationDedicatedCluster) Type() DestinationType { return DestinationTypeDedicated }

func (d *DestinationDedicatedCluster) ID() string { return strconv.FormatUint(d.ClusterID, 10) }

func (d *DestinationDedicatedCluster) IsDataplane() bool {
	return true
}

type DestinationByocCluster struct {
	BastionName string `json:"bastion_name,omitempty"`
}

func AsDestinationByocCluster(dest IDestination) (*DestinationByocCluster, bool) {
	d, ok := dest.(*DestinationByocCluster)
	return d, ok
}

func (d *DestinationByocCluster) Type() DestinationType { return DestinationTypeByoc }

func (d *DestinationByocCluster) ID() string {
	return d.BastionName
}

func (d *DestinationByocCluster) IsDataplane() bool {
	return true
}

type DestinationPremiumCluster struct {
	ClusterID uint64 `json:"cluster_id,string,omitempty"`
}

func AsDestinationPremiumCluster(dest IDestination) (*DestinationPremiumCluster, bool) {
	d, ok := dest.(*DestinationPremiumCluster)
	return d, ok
}

func (d *DestinationPremiumCluster) Type() DestinationType { return DestinationTypePremium }

func (d *DestinationPremiumCluster) ID() string {
	return strconv.FormatUint(d.ClusterID, 10)
}

func (d *DestinationPremiumCluster) IsDataplane() bool {
	return true
}

type DestinationPremiumResourcePool struct {
	ResourcePoolID uint64 `json:"resource_pool_id,string,omitempty"`
}

func AsDestinationPremiumResourcePool(dest IDestination) (*DestinationPremiumResourcePool, bool) {
	d, ok := dest.(*DestinationPremiumResourcePool)
	return d, ok
}

func (d *DestinationPremiumResourcePool) Type() DestinationType {
	return DestinationTypePremiumResourcePool
}

func (d *DestinationPremiumResourcePool) ID() string {
	return strconv.FormatUint(d.ResourcePoolID, 10)
}

func (d *DestinationPremiumResourcePool) IsDataplane() bool {
	return true
}

type DestinationUnion struct {
	ControlPlane        *DestinationControlPlane        `json:"control_plane,omitempty"`
	DedicatedCluster    *DestinationDedicatedCluster    `json:"dedicated_cluster,omitempty"`
	ServerlessCluster   *DestinationServerlessCluster   `json:"serverless_cluster,omitempty"`
	ByocCluster         *DestinationByocCluster         `json:"byoc_cluster,omitempty"`
	PremiumCluster      *DestinationPremiumCluster      `json:"premium_cluster,omitempty"`
	PremiumResourcePool *DestinationPremiumResourcePool `json:"premium_resource_pool,omitempty"`
}

func (d *DestinationUnion) Extract() IDestination {
	if d.ControlPlane != nil {
		return d.ControlPlane
	} else if d.DedicatedCluster != nil {
		return d.DedicatedCluster
	} else if d.ServerlessCluster != nil {
		return d.ServerlessCluster
	} else if d.ByocCluster != nil {
		return d.ByocCluster
	} else if d.PremiumCluster != nil {
		return d.PremiumCluster
	} else if d.PremiumResourcePool != nil {
		return d.PremiumResourcePool
	}

	return &DestinationUnspecified{}
}
