package grpcimp

import (
	"net"
	"os"
	"strings"
)

type Config struct {
	Network            string     `yaml:"network"`
	Address            string     `yaml:"address"`
	AdvertiseHost      string     `yaml:"advertise_host"`
	AdvertiseHostEnv   string     `yaml:"advertise_host_env"`
	AdvertiseScheme    string     `yaml:"advertise_scheme"`
	AdvertiseSchemeEnv string     `yaml:"advertise_scheme_env"`
	EnableReflection   bool       `yaml:"enable_reflection"`
	EnableHealth       bool       `yaml:"enable_health"`
	MaxRecvMsgSize     int        `yaml:"max_recv_msg_size"`
	MaxSendMsgSize     int        `yaml:"max_send_msg_size"`
	TLS                *TLSConfig `yaml:"tls"`
}

type TLSConfig struct {
	CertFile          string `yaml:"cert_file"`
	KeyFile           string `yaml:"key_file"`
	CAFile            string `yaml:"ca_file"`
	RequireClientCert bool   `yaml:"require_client_cert"`
}

// DiscoveryInvokeURI builds a discovery invoke URI from the gRPC config.
func (c *Config) DiscoveryInvokeURI() string {
	if c == nil {
		return ""
	}

	address := strings.TrimSpace(c.Address)
	addrHost, addrPort := splitHostPort(address)

	host := strings.TrimSpace(c.AdvertiseHost)
	if envKey := strings.TrimSpace(c.AdvertiseHostEnv); envKey != "" {
		if value := strings.TrimSpace(os.Getenv(envKey)); value != "" {
			host = value
		}
	}
	if host != "" {
		if parsedHost, parsedPort, err := net.SplitHostPort(host); err == nil && parsedPort != "" {
			host = strings.TrimSpace(parsedHost)
			addrPort = strings.TrimSpace(parsedPort)
		}
	}
	if host == "" {
		host = addrHost
	}
	if host == "" || host == "0.0.0.0" || host == "::" {
		return ""
	}
	if addrPort == "" {
		return ""
	}

	return net.JoinHostPort(host, addrPort)
}

func splitHostPort(address string) (string, string) {
	address = strings.TrimSpace(address)
	if address == "" {
		return "", ""
	}
	host, port, err := net.SplitHostPort(address)
	if err != nil {
		return "", ""
	}
	return strings.TrimSpace(host), strings.TrimSpace(port)
}
