package hysteria2

import (
	"fmt"
	"net/url"
	"strings"
)

// NormalizeShareLink accepts hysteria2:// or hy2:// share links (or already-normalized URI).
// Returns a canonical hysteria2:// URI suitable for the official client's `server` field.
func NormalizeShareLink(raw string) (string, string, error) {
	raw = strings.TrimSpace(raw)
	if raw == "" {
		return "", "", fmt.Errorf("empty hysteria2 URI")
	}

	remark := ""
	if i := strings.IndexByte(raw, '#'); i >= 0 {
		remark = strings.TrimSpace(raw[i+1:])
		if u, err := url.QueryUnescape(remark); err == nil {
			remark = u
		}
		raw = raw[:i]
	}

	lower := strings.ToLower(raw)
	switch {
	case strings.HasPrefix(lower, "hy2://"):
		raw = "hysteria2://" + raw[len("hy2://"):]
	case strings.HasPrefix(lower, "hysteria2://"):
		// ok
	default:
		return "", "", fmt.Errorf("ожидалась ссылка hysteria2:// или hy2://")
	}

	u, err := url.Parse(raw)
	if err != nil {
		return "", "", fmt.Errorf("parse hysteria2 URI: %w", err)
	}
	if u.Host == "" {
		return "", "", fmt.Errorf("hysteria2 URI missing host")
	}
	if u.Scheme != "hysteria2" {
		u.Scheme = "hysteria2"
	}
	return u.String(), remark, nil
}

// Detect returns true if raw looks like a Hysteria 2 share link.
func Detect(raw string) bool {
	lower := strings.ToLower(strings.TrimSpace(raw))
	return strings.HasPrefix(lower, "hysteria2://") || strings.HasPrefix(lower, "hy2://")
}

// HostPort extracts host and a single port for reachability checks.
func HostPort(shareURI string) (host, port string, err error) {
	normalized, _, err := NormalizeShareLink(shareURI)
	if err != nil {
		return "", "", err
	}
	u, err := url.Parse(normalized)
	if err != nil {
		return "", "", err
	}
	host = u.Hostname()
	port = u.Port()
	if port == "" {
		// Multi-port may be in Hostname() for weird parses; Host may be "ex.com:443,5000-6000"
		hostField := u.Host
		if h, p, ok := splitMultiPortHost(hostField); ok {
			return h, p, nil
		}
		port = "443"
	} else if strings.Contains(port, ",") || strings.Contains(port, "-") {
		port = firstPortToken(port)
	}
	if host == "" {
		return "", "", fmt.Errorf("нет хоста")
	}
	if port == "" {
		port = "443"
	}
	return host, port, nil
}

func splitMultiPortHost(hostField string) (host, port string, ok bool) {
	// example.com:443,5000-6000
	i := strings.LastIndex(hostField, ":")
	if i < 0 {
		return "", "", false
	}
	host = hostField[:i]
	port = firstPortToken(hostField[i+1:])
	if host == "" || port == "" {
		return "", "", false
	}
	return host, port, true
}

func firstPortToken(ports string) string {
	ports = strings.TrimSpace(ports)
	if ports == "" {
		return ""
	}
	part := ports
	if i := strings.IndexByte(ports, ','); i >= 0 {
		part = ports[:i]
	}
	if i := strings.IndexByte(part, '-'); i >= 0 {
		part = part[:i]
	}
	return strings.TrimSpace(part)
}
