// 命令 meshray-core：meshray-core 增强层的独立运行入口（类 frp 风格）。
//
// 直接以自定义 conn.Bind 接管 WireGuard 收发，使所有隧道密文流量经由本仓 9 层传输
// （Direct/TURN/WebRTC/...）而非裸 UDP。无需管理器即可在两台机器间建立加密隧道，
// 用于端到端验证 core 的收发能力。
//
// 用法：
//
//	meshray-core -genkey               # 生成私钥
//	meshray-core -c meshray-core.toml  # 按配置启动（默认 TOML，类 frp；兼容 .json）
package main

import (
	"flag"
	"fmt"
	"net"
	"os"
	"os/exec"
	"os/signal"
	"runtime"
	"strings"
	"syscall"

	meshraycore "git.zkcoi.com/zkcoi/meshray/core/engine"
	"git.zkcoi.com/zkcoi/meshray/core/connect"
	corebind "git.zkcoi.com/zkcoi/meshray/internal/ctr/corebind"
	"go.uber.org/zap"
	"golang.zx2c4.com/wireguard/conn"
	"golang.zx2c4.com/wireguard/device"
	"golang.zx2c4.com/wireguard/tun"
	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
)

func main() {
	cfgPath := flag.String("c", "meshray-core.toml", "配置文件路径（默认 TOML，类 frp；也兼容 .json）")
	genKey := flag.Bool("genkey", false, "仅生成私钥并打印后退出")
	flag.Parse()

	if *genKey {
		key, err := wgtypes.GeneratePrivateKey()
		if err != nil {
			fmt.Fprintln(os.Stderr, "生成私钥失败:", err)
			os.Exit(1)
		}
		fmt.Println(key.String())
		return
	}

	cfg, err := loadConfig(*cfgPath)
	if err != nil {
		fmt.Fprintln(os.Stderr, "加载配置失败:", err)
		os.Exit(1)
	}

	logger := newLogger()
	defer func() { _ = logger.Sync() }()

	// 1. 准备私钥：配置中给出则解析，否则生成并落盘
	priv, err := resolvePrivateKey(cfg, logger)
	if err != nil {
		logger.Fatal("私钥处理失败", zap.Error(err))
	}

	// 2. 创建 TUN 设备（用户态）。Windows 需已安装 Wintun 驱动。
	devName := "mrc0"
	tunDev, err := tun.CreateTUN(devName, cfg.MTU)
	if err != nil {
		logger.Fatal("创建 TUN 设备失败（Windows 需 Wintun 驱动）", zap.Error(err))
	}
	defer tunDev.Close()

	// 3. 创建 Bind：enhanced=自定义接管；native=裸 WG 默认 Bind
	var wgBind conn.Bind
	if cfg.Mode == "native" {
		logger.Info("以原生直连模式运行（裸 WG UDP）")
		wgBind = conn.NewDefaultBind()
	} else {
		logger.Info("以增强模式运行（9 层传输接管收发）")
		eb, eerr := corebind.NewEnhancedBind(cfg.ListenPort, cfg.NetworkID, logger)
		if eerr != nil {
			logger.Fatal("创建增强 Bind 失败", zap.Error(eerr))
		}
		wgBind = eb
	}

	wgLogger := &device.Logger{
		Verbosef: func(format string, args ...interface{}) { logger.Debug(fmt.Sprintf(format, args...)) },
		Errorf:   func(format string, args ...interface{}) { logger.Error(fmt.Sprintf(format, args...)) },
	}
	wgDev := device.NewDevice(tunDev, wgBind, wgLogger)
	defer wgDev.Close()

	// 4. 组装 WG 配置（私钥 / 监听端口 / 各 peer）
	var sb strings.Builder
	fmt.Fprintf(&sb, "private_key=%s\nlisten_port=%d\n", priv.String(), cfg.ListenPort)
	for _, p := range cfg.Peers {
		pub, perr := wgtypes.ParseKey(p.PublicKey)
		if perr != nil {
			logger.Fatal("对端公钥解析失败", zap.String("public_key", p.PublicKey), zap.Error(perr))
		}
		fmt.Fprintf(&sb, "public_key=%s\n", pub.String())
		if p.Endpoint != "" {
			fmt.Fprintf(&sb, "endpoint=%s\n", p.Endpoint)
		}
		for _, a := range p.AllowedIPs {
			fmt.Fprintf(&sb, "allowed_ip=%s\n", a)
		}
		fmt.Fprintf(&sb, "persistent_keepalive=25\n")
	}
	if err := wgDev.IpcSet(sb.String()); err != nil {
		logger.Fatal("配置 WireGuard 设备失败", zap.Error(err))
	}

	// 5. 增强模式：把对端候选（endpoint）注入引擎触发 9 层拨号
	if eb, ok := wgBind.(*corebind.EnhancedBind); ok {
		eng := eb.Engine()

		// 5.0 下达 ICE 配置（STUN/TURN），手动 TURN/WebRTC 层级必需
		if len(cfg.ICE.STUN) > 0 || len(cfg.ICE.TURN) > 0 {
			turnCfgs := make([]connect.TURNServerConfig, 0, len(cfg.ICE.TURN))
			for _, t := range cfg.ICE.TURN {
				turnCfgs = append(turnCfgs, connect.TURNServerConfig{URLs: []string{t}})
			}
			ice := connect.ICEConfig{
				STUNServers: cfg.ICE.STUN,
				TURNServers: turnCfgs,
			}
			if err := eng.SetICEConfig(ice); err != nil {
				logger.Error("下达 ICE 配置失败", zap.Error(err))
			}
		}

		// 5.1 应用传输层级策略：auto=默认 9 层自动降级；manual=仅用配置的 layers
		if cfg.LayerStrategy == "manual" {
			if len(cfg.Layers) == 0 {
				logger.Fatal("layer_strategy=manual 但 layers 为空")
			}
			layers, perr := parseLayers(cfg.Layers)
			if perr != nil {
				logger.Fatal("解析手动层级失败", zap.Error(perr))
			}
			eng.SetLayerOrder(layers)
			if len(layers) == 1 {
				logger.Info("手动层级模式：强制固定层（禁用降级）",
					zap.String("layer", layers[0].String()))
			} else {
				logger.Info("手动层级模式：自定义降级顺序",
					zap.Strings("layers", cfg.Layers))
			}
		} else {
			logger.Info("自动层级模式：9 层自动降级",
				zap.Int("default_layers", len(connect.DefaultLayerOrder)))
		}

		// 5.2 注入对端候选，触发拨号
		for _, p := range cfg.Peers {
			if p.Endpoint == "" {
				continue
			}
			if err := eng.NotifyPeerInfo(p.PublicKey, []meshraycore.Candidate{{Addr: p.Endpoint}}); err != nil {
				logger.Error("注入对端候选失败", zap.String("peer", p.PublicKey), zap.Error(err))
			}
		}
	}

	// 6. 启动设备并配置隧道 IP
	if err := wgDev.Up(); err != nil {
		logger.Fatal("启动 WireGuard 设备失败", zap.Error(err))
	}
	devName, nameErr := tunDev.Name()
	if nameErr != nil {
		logger.Warn("获取 TUN 设备名失败", zap.Error(nameErr))
		devName = "mrc0"
	}
	assignInterfaceIP(devName, cfg.InterfaceIP, logger)

	logger.Info("meshray-core 已启动",
		zap.String("network_id", cfg.NetworkID),
		zap.String("mode", cfg.Mode),
		zap.String("device", devName),
		zap.String("interface", cfg.InterfaceIP))

	// 7. 阻塞等待退出信号
	sig := make(chan os.Signal, 1)
	signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
	<-sig
	logger.Info("正在退出...")
}

// resolvePrivateKey 返回私钥：配置给出则解析，否则生成并写入 private_key_file
func resolvePrivateKey(cfg *Config, logger *zap.Logger) (wgtypes.Key, error) {
	if cfg.PrivateKey != "" {
		return wgtypes.ParseKey(cfg.PrivateKey)
	}
	key, err := wgtypes.GeneratePrivateKey()
	if err != nil {
		return wgtypes.Key{}, err
	}
	if cfg.PrivateKeyFile != "" {
		if werr := os.WriteFile(cfg.PrivateKeyFile, []byte(key.String()), 0600); werr != nil {
			logger.Warn("写入私钥文件失败", zap.Error(werr))
		} else {
			logger.Info("已生成并写入私钥", zap.String("file", cfg.PrivateKeyFile))
		}
	}
	return key, nil
}

// assignInterfaceIP 给隧道接口分配 IP 并 up（best-effort，失败仅告警）
func assignInterfaceIP(name, cidr string, logger *zap.Logger) {
	if cidr == "" {
		return
	}
	ip, ipNet, err := net.ParseCIDR(cidr)
	if err != nil {
		logger.Error("解析隧道 IP 失败", zap.String("cidr", cidr), zap.Error(err))
		return
	}
	switch runtime.GOOS {
	case "linux":
		run(logger, "ip", "addr", "add", cidr, "dev", name)
		run(logger, "ip", "link", "set", name, "up")
	case "windows":
		// ipNet.Mask 已是网络掩码字节，转点分十进制
		m := ipNet.Mask
		maskStr := fmt.Sprintf("%d.%d.%d.%d", m[0], m[1], m[2], m[3])
		run(logger, "netsh", "interface", "ip", "set", "address",
			"name="+name, "static", ip.String(), maskStr)
	default:
		logger.Warn("不支持的平台，请手动配置隧道 IP", zap.String("os", runtime.GOOS))
	}
}

// run 执行外部命令（best-effort，输出仅调试）
func run(logger *zap.Logger, name string, args ...string) {
	cmd := exec.Command(name, args...)
	out, err := cmd.CombinedOutput()
	if err != nil {
		logger.Warn("执行命令失败（可忽略，手动配置即可）",
			zap.String("cmd", name), zap.String("args", strings.Join(args, " ")),
			zap.Error(err), zap.String("output", string(out)))
	}
}

// newLogger 创建生产级 logger
func newLogger() *zap.Logger {
	l, err := zap.NewProduction()
	if err != nil {
		l = zap.NewNop()
	}
	return l
}

// parseLayers 将配置中的层级名列表解析为 connect.Layer 列表，任一无法解析则返回错误
func parseLayers(names []string) ([]connect.Layer, error) {
	layers := make([]connect.Layer, 0, len(names))
	for _, n := range names {
		l, ok := connect.ParseLayer(n)
		if !ok {
			return nil, fmt.Errorf("未知传输层: %q", n)
		}
		layers = append(layers, l)
	}
	return layers, nil
}
