package utils

import (
	"context"
	"encoding/json"
	"fmt"
	"net"
	"os/exec"
	"runtime"
	"strings"
	"time"

	"github.com/civet148/log"
)

/* ---------- 获取本机同网段 IP ---------- */

func getGatewayIP() (string, error) {
	var cmd *exec.Cmd
	switch runtime.GOOS {
	case "linux":
		cmd = exec.Command("sh", "-c", "ip route | grep default | awk '{print $3}'")
	case "darwin":
		cmd = exec.Command("sh", "-c", "netstat -rn | grep default | awk '{print $2}'")
	default:
		return "", fmt.Errorf("unsupported OS")
	}
	out, err := cmd.Output()
	if err != nil {
		return "", err
	}
	return strings.TrimSpace(string(out)), nil
}

func ipInSameSubnet(ip1 net.IP, ip2 net.IP, mask net.IPMask) bool {
	if mask == nil {
		return false
	}
	return ip1.Mask(mask).Equal(ip2.Mask(mask))
}

func GetLocalIPSameAsGW() string {
	gwStr, err := getGatewayIP()
	if err != nil {
		return "127.0.0.1"
	}
	gw := net.ParseIP(gwStr)

	ifaces, _ := net.Interfaces()
	for _, iface := range ifaces {
		if iface.Flags&net.FlagUp == 0 {
			continue
		}
		addrs, _ := iface.Addrs()
		for _, a := range addrs {
			var ip net.IP
			var mask net.IPMask
			switch v := a.(type) {
			case *net.IPNet:
				ip = v.IP
				mask = v.Mask
			case *net.IPAddr:
				ip = v.IP
			}
			if ip == nil || ip.IsLoopback() || ip.To4() == nil {
				continue
			}
			if ipInSameSubnet(ip, gw, mask) {
				return ip.String()
			}
		}
	}
	return "127.0.0.1"
}

func IsValidIP(ip string) bool {
	if ip == "" || ip == "127.0.0.1" {
		return false
	}
	p := net.ParseIP(ip)
	return p != nil && !p.IsLoopback() && !p.IsUnspecified() &&
		!p.IsLinkLocalMulticast() && !p.IsLinkLocalUnicast()
}

/* ---------- UDP 广播 ---------- */

type BroadcastMessage struct {
	Type string `json:"type"`
	IP   string `json:"ip"`
	Port int    `json:"port"`
	Name string `json:"name"`
}

// StartBroadcast 启动 UDP 广播；ctx 取消时自动退出
func StartBroadcast(ctx context.Context, port, interval int, name string) {
	go func() {
		var prevIP string
		var conn *net.UDPConn

		for {
			select {
			case <-ctx.Done():
				if conn != nil {
					conn.Close()
				}
				return
			default:
			}

			curIP := GetLocalIPSameAsGW()
			if !IsValidIP(curIP) {
				time.Sleep(time.Duration(interval) * time.Second)
				continue
			}

			if curIP != prevIP || conn == nil {
				if conn != nil {
					conn.Close()
				}
				addr := net.UDPAddr{IP: net.IPv4bcast, Port: port}
				c, err := net.DialUDP("udp4", nil, &addr)
				if err != nil {
					log.Warnf("UDP 连接失败: %v", err)
					time.Sleep(time.Duration(interval) * time.Second)
					continue
				}
				conn = c
				prevIP = curIP
				log.Infof("绑定新 IP 广播: %s", curIP)
			}

			msg := BroadcastMessage{
				Type: "ai_server_announce",
				IP:   curIP,
				Port: port,
				Name: name,
			}
			data, _ := json.Marshal(msg)
			if _, err := conn.Write(data); err != nil {
				log.Warnf("广播失败: %v", err)
			}
			time.Sleep(time.Duration(interval) * time.Second)
		}
	}()
}
