package metrics

import "sync/atomic"

type poolStatsProviderHolder struct {
	provider PoolStatsProvider
}

type preparedStmtCacheStatsProviderHolder struct {
	provider PreparedStmtCacheStatsProvider
}

type connectionStatsProviderHolder struct {
	provider ConnectionStatsProvider
}

var (
	poolStatsProvider         atomic.Value // poolStatsProviderHolder
	preparedStmtStatsProvider atomic.Value // preparedStmtCacheStatsProviderHolder
	connectionStatsProvider   atomic.Value // connectionStatsProviderHolder
)

// SetPoolStatsProvider overrides the pool stats provider used by the metrics collector.
func SetPoolStatsProvider(provider PoolStatsProvider) {
	poolStatsProvider.Store(poolStatsProviderHolder{provider: provider})
}

// SetPreparedStmtCacheStatsProvider overrides the prepared statement cache stats provider used by the metrics collector.
func SetPreparedStmtCacheStatsProvider(provider PreparedStmtCacheStatsProvider) {
	preparedStmtStatsProvider.Store(preparedStmtCacheStatsProviderHolder{provider: provider})
}

// SetConnectionStatsProvider overrides the CQL connection stats provider used by the metrics collector.
func SetConnectionStatsProvider(provider ConnectionStatsProvider) {
	connectionStatsProvider.Store(connectionStatsProviderHolder{provider: provider})
}

func activePoolStatsProvider() PoolStatsProvider {
	if value := poolStatsProvider.Load(); value != nil {
		if holder, ok := value.(poolStatsProviderHolder); ok {
			return holder.provider
		}
	}
	return nil
}

func activePreparedStmtCacheStatsProvider() PreparedStmtCacheStatsProvider {
	if value := preparedStmtStatsProvider.Load(); value != nil {
		if holder, ok := value.(preparedStmtCacheStatsProviderHolder); ok {
			return holder.provider
		}
	}
	return nil
}

func activeConnectionStatsProvider() ConnectionStatsProvider {
	if value := connectionStatsProvider.Load(); value != nil {
		if holder, ok := value.(connectionStatsProviderHolder); ok {
			return holder.provider
		}
	}
	return nil
}
