package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"net"
	"os/exec"
	"syscall"
	"time"
	"unsafe"

	MQTT "github.com/eclipse/paho.mqtt.golang"
)

// 配置常量
const (
	defaultMQTTHost        = "192.168.1.2"          // 默认MQTT服务器地址
	mqttPort               = 1883                   // MQTT端口
	subscriptionTopic      = "computer/admin"       // 订阅主题
	publishingTopic        = "computer/clients"     // 发布主题
	connectTimeoutDuration = 5 * time.Second        // 连接超时时间
	publishTimeoutDuration = 3 * time.Second        // 发布超时时间
	disconnectWaitDuration = 250 * time.Millisecond // 断开连接等待时间
	messageBoxWait         = 3 * time.Second        // 消息框显示时长

)

var (
	mqttClient = &MqttClient{} // MQTT客户端实例
	username   string          // 客户端用户名（MAC地址）
)

func init() {
	// 获取MAC地址作为用户名
	username = getMacAddress()
	if username == "" {
		log.Fatal(" 无法获取MAC地址，程序终止")
	}

	// 初始化MQTT连接
	if err := connectToMQTT(defaultMQTTHost); err != nil {
		log.Printf(" MQTT初始化连接失败: %v", err)
	}
	m := make(map[string]string)
	m["username"] = username
	m["message"] = "connect"
	by, _ := json.Marshal(m)
	mqttClient.client.Publish(publishingTopic, byte(0), false, by)

}

func main() {
	// 保持程序运行（监听退出信号）
	log.Println(" 程序已启动，等待MQTT消息...")
	<-make(chan struct{})
}

// 连接MQTT服务器
func connectToMQTT(host string) error {
	brokerURL := fmt.Sprintf("tcp://%s:%d", host, mqttPort)
	mqttClient.initialize(brokerURL, username, username, username) // 客户端ID使用MAC地址

	// 执行连接
	if err := mqttClient.connect(); err != nil {
		return fmt.Errorf("连接失败: %w", err)
	}

	// 订阅消息主题
	if err := mqttClient.subscribe(subscriptionTopic, handleMessage); err != nil {
		mqttClient.disconnect()
		return fmt.Errorf("订阅失败: %w", err)
	}

	log.Printf("[%s]  MQTT连接成功，客户端ID: %s", time.Now().Format("2006-01-02 15:04:05"), username)
	return nil
}

// 消息处理函数
func handleMessage(client MQTT.Client, msg MQTT.Message) {
	var payload map[string]string
	if err := json.Unmarshal(msg.Payload(), &payload); err != nil {
		log.Printf(" 消息解析失败: %v, 内容: %s", err, string(msg.Payload()))
		return
	}

	// 校验目标客户端
	if payload["username"] != username {
		log.Printf(" 忽略非目标消息，目标用户: %s", payload["username"])
		return
	}
	fmt.Println(payload, time.Now().Format("2006-01-02 15:04:05"))
	// 处理命令
	switch payload["message"] {
	case "shutdown":
		executeSystemCommand("shutdown", "-s", "-t", "0")
	case "reboot":
		executeSystemCommand("shutdown", "-r", "-t", "0")
	default:
		go func() {
			showWindowsMessage("系统通知", payload["message"])
		}()
	}
}

// 执行系统命令（带安全校验）
func executeSystemCommand(name string, args ...string) {
	// 危险命令过滤（可根据需求扩展）
	dangerousCommands := map[string]bool{"rm": true, "mkfs": true, "chmod": true}
	if dangerousCommands[name] {
		log.Printf(" 禁止执行危险命令: %s", name)
		return
	}

	cmd := exec.Command(name, args...)
	if output, err := cmd.CombinedOutput(); err != nil {
		log.Printf(" 命令执行失败: %v, 输出: %s", err, string(output))
	} else {
		log.Printf(" 命令执行成功: %s", name)
	}
}

// 显示Windows消息框
func showWindowsMessage(title, message string) {
	user32 := syscall.NewLazyDLL("user32.dll")
	messageBox := user32.NewProc("MessageBoxW")

	// 转换为UTF-16指针
	titleUTF16, err := syscall.UTF16PtrFromString(title)
	if err != nil {
		log.Printf(" 标题转换失败: %v", err)
		return
	}
	messageUTF16, err := syscall.UTF16PtrFromString(message)
	if err != nil {
		log.Printf(" 消息转换失败: %v", err)
		return
	}

	// 显示消息框（类型为信息图标）
	messageBox.Call(
		uintptr(0),                            // 父窗口句柄
		uintptr(unsafe.Pointer(messageUTF16)), // 消息内容
		uintptr(unsafe.Pointer(titleUTF16)),   // 标题
		uintptr(0x00000040),                   // 信息图标 + 确定按钮
	)

	// 等待自动关闭
	time.Sleep(messageBoxWait)
}

// MQTT客户端结构体
type MqttClient struct {
	client MQTT.Client
}

// 初始化客户端配置
func (c *MqttClient) initialize(broker, user, pass, clientID string) {
	opts := MQTT.NewClientOptions()
	opts.AddBroker(broker)
	opts.SetUsername(username)
	opts.SetPassword(pass)
	opts.SetClientID(clientID)
	opts.SetAutoReconnect(false) // 使用手动重连逻辑
	opts.SetConnectRetry(true)
	opts.SetConnectRetryInterval(2 * time.Second)
	opts.SetOnConnectHandler(func(client MQTT.Client) {
		log.Println(" MQTT连接已建立")
	})
	opts.SetConnectionLostHandler(func(client MQTT.Client, err error) {
		log.Printf(" MQTT连接断开: %v", err)
	})

	c.client = MQTT.NewClient(opts)
}

// 执行连接
func (c *MqttClient) connect() error {
	if c.client.IsConnected() {
		return nil
	}

	token := c.client.Connect()
	if !token.WaitTimeout(connectTimeoutDuration) {
		return errors.New("连接超时")
	}
	return token.Error()
}

// 断开连接
func (c *MqttClient) disconnect() {
	if c.client.IsConnected() {
		c.client.Disconnect(uint(disconnectWaitDuration))
		log.Println(" MQTT连接已断开")
	}
}

// 订阅主题
func (c *MqttClient) subscribe(topic string, handler MQTT.MessageHandler) error {
	if !c.client.IsConnected() {
		return errors.New("未连接到MQTT服务器")
	}

	token := c.client.Subscribe(topic, byte(2), handler)
	if !token.WaitTimeout(connectTimeoutDuration) {
		return errors.New("订阅超时")
	}
	return token.Error()
}

// 获取MAC地址（优化版）
func getMacAddress() string {
	ifaces, err := net.Interfaces()
	if err != nil {
		log.Printf(" 获取网络接口失败: %v", err)
		return ""
	}

	for _, iface := range ifaces {
		// 过滤无效接口（回环/未激活/无MAC）
		if (iface.Flags&net.FlagLoopback) != 0 ||
			(iface.Flags&net.FlagUp) == 0 ||
			len(iface.HardwareAddr) == 0 {
			continue
		}

		return iface.HardwareAddr.String() // 返回第一个有效MAC地址
	}

	log.Println(" 未找到有效MAC地址")
	return ""
}

//原理是 MQTT服务器 判断当有电脑客户端连接时,发送http post到这个服务器 内容有 username,message (上线还是下线)
