package chain

import (
	"strings"

	"github.com/tech/sendico/pkg/merrors"
	chainv1 "github.com/tech/sendico/pkg/proto/gateway/chain/v1"
)

func AssetString(asset *chainv1.Asset) string {
	if asset == nil {
		return ""
	}
	symbol := strings.ToUpper(strings.TrimSpace(asset.GetTokenSymbol()))
	if symbol == "" {
		return ""
	}
	suffix := assetSuffix(asset.GetChain())
	if suffix == "" {
		return symbol
	}
	return symbol + "-" + suffix
}

func ParseAsset(assetString, network, tokenSymbol, contractAddress string) (*chainv1.Asset, error) {
	token := strings.TrimSpace(tokenSymbol)
	net := strings.TrimSpace(network)
	contract := strings.TrimSpace(contractAddress)

	if token == "" {
		token = TokenFromAssetString(assetString)
	}
	if net == "" {
		net = NetworkFromAssetString(assetString)
	}
	if token == "" {
		return nil, merrors.InvalidArgument("asset: token_symbol is required")
	}
	chain := NetworkFromString(net)
	if chain == chainv1.ChainNetwork_CHAIN_NETWORK_UNSPECIFIED {
		return nil, merrors.InvalidArgument("asset: network is required")
	}
	return &chainv1.Asset{
		Chain:           chain,
		TokenSymbol:     strings.ToUpper(token),
		ContractAddress: contract,
	}, nil
}

func TokenFromAssetString(asset string) string {
	trimmed := strings.TrimSpace(asset)
	if trimmed == "" {
		return ""
	}
	if idx := strings.Index(trimmed, "-"); idx > 0 {
		return trimmed[:idx]
	}
	return trimmed
}

func NetworkFromAssetString(asset string) string {
	trimmed := strings.TrimSpace(asset)
	if trimmed == "" {
		return ""
	}
	idx := strings.Index(trimmed, "-")
	if idx < 0 {
		return ""
	}
	return strings.TrimSpace(trimmed[idx+1:])
}

func NetworkName(chain chainv1.ChainNetwork) string {
	if chain == chainv1.ChainNetwork_CHAIN_NETWORK_UNSPECIFIED {
		return ""
	}
	if name, ok := chainv1.ChainNetwork_name[int32(chain)]; ok {
		return strings.TrimPrefix(name, "CHAIN_NETWORK_")
	}
	return ""
}

func NetworkAlias(chain chainv1.ChainNetwork) string {
	switch chain {
	case chainv1.ChainNetwork_CHAIN_NETWORK_ETHEREUM_MAINNET:
		return "ETHEREUM_MAINNET"
	case chainv1.ChainNetwork_CHAIN_NETWORK_TRON_MAINNET:
		return "TRON_MAINNET"
	case chainv1.ChainNetwork_CHAIN_NETWORK_TRON_NILE:
		return "TRON_NILE"
	case chainv1.ChainNetwork_CHAIN_NETWORK_ARBITRUM_ONE:
		return "ARBITRUM_ONE"
	case chainv1.ChainNetwork_CHAIN_NETWORK_ARBITRUM_SEPOLIA:
		return "ARBITRUM_SEPOLIA"
	default:
		name := NetworkName(chain)
		if name == "" {
			fallback := strings.TrimPrefix(strings.TrimSpace(chain.String()), "CHAIN_NETWORK_")
			return strings.ToUpper(fallback)
		}
		return strings.ToUpper(name)
	}
}

func NetworkFromString(value string) chainv1.ChainNetwork {
	normalized := normalizeNetworkString(value)
	if normalized == "" {
		return chainv1.ChainNetwork_CHAIN_NETWORK_UNSPECIFIED
	}
	if val, ok := chainv1.ChainNetwork_value[normalized]; ok {
		return chainv1.ChainNetwork(val)
	}
	switch normalized {
	case "ETH", "ETHEREUM", "ETH_MAINNET", "ETHEREUM_MAINNET":
		return chainv1.ChainNetwork_CHAIN_NETWORK_ETHEREUM_MAINNET
	case "TRON", "TRON_MAINNET":
		return chainv1.ChainNetwork_CHAIN_NETWORK_TRON_MAINNET
	case "TRON_NILE":
		return chainv1.ChainNetwork_CHAIN_NETWORK_TRON_NILE
	case "ARB", "ARBITRUM", "ARBITRUM_ONE":
		return chainv1.ChainNetwork_CHAIN_NETWORK_ARBITRUM_ONE
	case "ARBITRUM_SEPOLIA":
		return chainv1.ChainNetwork_CHAIN_NETWORK_ARBITRUM_SEPOLIA
	}
	if !strings.HasPrefix(normalized, "CHAIN_NETWORK_") {
		normalized = "CHAIN_NETWORK_" + normalized
	}
	if val, ok := chainv1.ChainNetwork_value[normalized]; ok {
		return chainv1.ChainNetwork(val)
	}
	return chainv1.ChainNetwork_CHAIN_NETWORK_UNSPECIFIED
}

func normalizeNetworkString(value string) string {
	trimmed := strings.TrimSpace(value)
	if trimmed == "" {
		return ""
	}
	normalized := strings.ToUpper(trimmed)
	normalized = strings.ReplaceAll(normalized, " ", "_")
	normalized = strings.ReplaceAll(normalized, "-", "_")
	return normalized
}

func assetSuffix(chain chainv1.ChainNetwork) string {
	switch chain {
	case chainv1.ChainNetwork_CHAIN_NETWORK_ETHEREUM_MAINNET:
		return "ETH"
	case chainv1.ChainNetwork_CHAIN_NETWORK_ARBITRUM_ONE:
		return "ARB"
	case chainv1.ChainNetwork_CHAIN_NETWORK_TRON_MAINNET:
		return "TRC20"
	case chainv1.ChainNetwork_CHAIN_NETWORK_TRON_NILE:
		return "TRC20"
	default:
		return ""
	}
}
