package hysteria2

import (
	"fmt"
	"os"
	"strings"

	"vpnclient/internal/config"
)

func writeRuntimeConfig(path string, profile config.Profile) error {
	ep, err := ParseEndpoint(profile.Proxy)
	if err != nil {
		return err
	}
	var insecureOverride *bool
	if profile.Hy2Insecure {
		v := true
		insecureOverride = &v
	}
	ep.ApplyOverrides(profile.Hy2SNI, profile.Hy2Obfs, profile.Hy2ObfsPassword, profile.Hy2PinSHA256, insecureOverride)

	socks := "127.0.0.1:1080"
	httpListen := "127.0.0.1:1081"
	if hp, ok := profile.SOCKSListenHostPort(); ok {
		socks = hp
	}
	if hp, ok := profile.HTTPListenHostPort(); ok {
		httpListen = hp
	}

	var b strings.Builder
	b.WriteString("# generated by Navis — do not edit\n")

	// Expanded form so congestion/obfs/tls can coexist with auth.
	b.WriteString("server: " + yamlQuote(ep.Server) + "\n")
	if ep.Auth != "" {
		b.WriteString("auth: " + yamlQuote(ep.Auth) + "\n")
	}

	if ep.SNI != "" || ep.Insecure || ep.PinSHA256 != "" {
		b.WriteString("tls:\n")
		if ep.SNI != "" {
			b.WriteString("  sni: " + yamlQuote(ep.SNI) + "\n")
		}
		if ep.Insecure {
			b.WriteString("  insecure: true\n")
		}
		if ep.PinSHA256 != "" {
			b.WriteString("  pinSHA256: " + yamlQuote(ep.PinSHA256) + "\n")
		}
	}

	obfs := strings.ToLower(strings.TrimSpace(ep.Obfs))
	if obfs == "" {
		obfs = strings.ToLower(strings.TrimSpace(profile.Hy2Obfs))
	}
	obfsPass := ep.ObfsPassword
	if obfsPass == "" {
		obfsPass = profile.Hy2ObfsPassword
	}
	switch obfs {
	case "salamander":
		if obfsPass == "" {
			return fmt.Errorf("hysteria2: salamander требует пароль (obfs-password)")
		}
		b.WriteString("obfs:\n")
		b.WriteString("  type: salamander\n")
		b.WriteString("  salamander:\n")
		b.WriteString("    password: " + yamlQuote(obfsPass) + "\n")
	case "gecko":
		if obfsPass == "" {
			return fmt.Errorf("hysteria2: gecko требует пароль (obfs-password)")
		}
		b.WriteString("obfs:\n")
		b.WriteString("  type: gecko\n")
		b.WriteString("  gecko:\n")
		b.WriteString("    password: " + yamlQuote(obfsPass) + "\n")
	}

	// Congestion: BBR (default) or reno. Bandwidth enables Brutal instead.
	up := ParseBandwidthMbps(profile.Hy2BandwidthUp)
	down := ParseBandwidthMbps(profile.Hy2BandwidthDown)
	cong := strings.ToLower(strings.TrimSpace(profile.Hy2Congestion))
	if cong == "" {
		cong = "bbr"
	}
	bbrProfile := strings.ToLower(strings.TrimSpace(profile.Hy2BBRProfile))
	if bbrProfile == "" {
		bbrProfile = "standard"
	}

	if up != "" || down != "" {
		b.WriteString("bandwidth:\n")
		if up != "" {
			b.WriteString("  up: " + yamlQuote(up) + "\n")
		}
		if down != "" {
			b.WriteString("  down: " + yamlQuote(down) + "\n")
		}
	} else {
		// No Brutal → use BBR/reno
		b.WriteString("congestion:\n")
		b.WriteString("  type: " + yamlQuote(cong) + "\n")
		if cong == "bbr" {
			b.WriteString("  bbrProfile: " + yamlQuote(bbrProfile) + "\n")
		}
	}

	if hop := strings.TrimSpace(profile.Hy2HopInterval); hop != "" {
		b.WriteString("transport:\n")
		b.WriteString("  type: udp\n")
		b.WriteString("  udp:\n")
		b.WriteString("    hopInterval: " + yamlQuote(hop) + "\n")
	}

	if profile.Hy2FastOpen {
		b.WriteString("fastOpen: true\n")
	}
	if profile.Hy2Lazy {
		b.WriteString("lazy: true\n")
	}

	// "Masquerade extras" on client = look like normal HTTPS via SNI already above;
	// optional ALPN hint kept for compatibility with some panels.
	if alpn := strings.TrimSpace(profile.Hy2ALPN); alpn != "" {
		// Official client uses TLS defaults; keep as comment for operators.
		b.WriteString("# alpn-hint: " + yamlQuote(alpn) + "\n")
	}

	b.WriteString("socks5:\n")
	b.WriteString("  listen: " + yamlQuote(socks) + "\n")
	b.WriteString("http:\n")
	b.WriteString("  listen: " + yamlQuote(httpListen) + "\n")

	return writeFile(path, b.String())
}

func writeFile(path, content string) error {
	return os.WriteFile(path, []byte(content), 0o600)
}
