package types

import (
	"sync"

	sdk "github.com/pokt-network/pocket-core/types"
)

// HostedBlockchain" - An object that represents a local hosted non-native blockchain
type HostedBlockchain struct {
	ID        string    `json:"id"`         // network identifier of the hosted blockchain
	URL       string    `json:"url"`        // url of the hosted blockchain
	BasicAuth BasicAuth `json:"basic_auth"` // Optional; basic http auth
}

// BasicAuth is an optional http auth mechanism if the URL does not embed the secrets directly.
// Removed from examples & documentation for clarity.
type BasicAuth struct {
	Username string `json:"username"`
	Password string `json:"password"`
}

// HostedBlockchains" - An object that represents the local hosted non-native blockchains
type HostedBlockchains struct {
	M map[string]HostedBlockchain // M[addr] -> addr, url
	L sync.RWMutex
}

// "Contains" - Checks to see if the hosted chain is within the HostedBlockchains object
func (c *HostedBlockchains) Contains(id string) bool {
	c.L.RLock()
	defer c.L.RUnlock()
	// quick map check
	_, found := c.M[id]
	return found
}

// "GetChainURL" - Returns the url or error of the hosted blockchain using the hex network identifier
func (c *HostedBlockchains) GetChain(id string) (chain HostedBlockchain, err sdk.Error) {
	c.L.RLock()
	defer c.L.RUnlock()
	// map check
	res, found := c.M[id]
	if !found {
		return HostedBlockchain{}, NewErrorChainNotHostedError(ModuleName)
	}
	return res, nil
}

// "GetChainURL" - Returns the url or error of the hosted blockchain using the hex network identifier
func (c *HostedBlockchains) GetChainURL(id string) (url string, err sdk.Error) {
	chain, err := c.GetChain(id)
	if err != nil {
		return "", err
	}
	return chain.URL, nil
}

// "Validate" - Validates the hosted blockchain object
func (c *HostedBlockchains) Validate() error {
	c.L.RLock()
	defer c.L.RUnlock()
	// loop through all of the chains
	for _, chain := range c.M {
		// validate not empty
		if chain.ID == "" || chain.URL == "" {
			return NewInvalidHostedChainError(ModuleName)
		}
		// validate the merkleHash
		if err := NetworkIdentifierVerification(chain.ID); err != nil {
			return err
		}
	}
	return nil
}
