package task

import (
	"context"
	"fmt"
	"gitee.ltd/lxh/logger/log"
	jsoniter "github.com/json-iterator/go"
	"golang.org/x/exp/slices"
	"strings"
	"time"
	"wireguard-ui/component"
	"wireguard-ui/global/client"
	"wireguard-ui/global/constant"
	"wireguard-ui/model"
	"wireguard-ui/service"
	"wireguard-ui/utils"
)

type NetworkClientImpl interface {
	ClientOfflineNotify() // 客户端离线通知
}

type networkClient struct{}

func NetworkClient() NetworkClientImpl {
	return networkClient{}
}

// ClientOfflineNotify
// @description: 客户端离线通知
// @receiver c
// @return error
func (c networkClient) ClientOfflineNotify() {
	log.Debugf("开始执行离线通知任务")
	// 开始扫描已经链接过的客户端
	connectedPeers, err := component.Wireguard().GetClients()
	if err != nil {
		log.Errorf("获取已连接客户端失败: %v", err.Error())
		return
	}

	// 查询一下通知配置
	code, err := service.Setting().GetByCode("WECHAT_NOTIFY")
	if err != nil {
		log.Errorf("获取微信通知配置失败: %v", err.Error())
		return
	}

	// 查询出所有配置了离线通知的客户端
	var clients []model.Client
	if err := client.DB.Where("offline_monitoring = ?", 1).Find(&clients).Error; err != nil {
		return
	}

	if len(clients) <= 0 {
		return
	}

	for _, peer := range connectedPeers {
		var clientName string
		if !slices.ContainsFunc(clients, func(cli model.Client) bool {
			isExist := peer.PublicKey.String() == jsoniter.Get([]byte(cli.Keys), "publicKey").ToString()
			if isExist {
				clientName = cli.Name
			}
			return isExist
		}) {
			continue
		}

		online := time.Since(peer.LastHandshakeTime).Minutes() < 3
		log.Debugf("客户端[%v]在线状态: %v，离线时间: %v", clientName, online, time.Since(peer.LastHandshakeTime).Minutes())

		var ipAllocation string
		for _, iaip := range peer.AllowedIPs {
			ipAllocation += iaip.String() + ","
		}
		// 去除一下最右边的逗号
		if len(ipAllocation) > 0 {
			ipAllocation = strings.TrimRight(ipAllocation, ",")
		}

		// 如果存在,判断离线时间
		if !online {
			// 已经离线,发送通知
			msg := fmt.Sprintf(`[离线通知]
客户端名称 : %v
客户端IP : %v
最后在线时间 : %v`, clientName, ipAllocation, peer.LastHandshakeTime.Format("2006-01-02 15:04:05"))
			err := utils.WechatNotify(code).SendTextMessage(msg)
			if err != nil {
				log.Errorf("微信消息[%v]通知失败: %v", msg, err.Error())
				continue
			}

			// 离线了,设置离线标识
			client.Redis.Set(context.Background(), fmt.Sprintf("%s%s", constant.ClientOffline, utils.Hash().MD5(ipAllocation)), true, 0)
		} else {
			// 判断是否存在缓存
			if client.Redis.Exists(context.Background(), fmt.Sprintf("%s%s", constant.ClientOffline, utils.Hash().MD5(ipAllocation))).Val() > 0 {
				// 存在,删除离线标识
				client.Redis.Del(context.Background(), fmt.Sprintf("%s%s", constant.ClientOffline, utils.Hash().MD5(ipAllocation)))
				// 微信通知该客户端已经上线
				msg := fmt.Sprintf(`[上线通知]
客户端名称 : %v
客户端IP : %v
最后在线时间 : %v`, clientName, ipAllocation, peer.LastHandshakeTime.Format("2006-01-02 15:04:05"))
				err := utils.WechatNotify(code).SendTextMessage(msg)
				if err != nil {
					log.Errorf("微信消息[%v]通知失败: %v", msg, err.Error())
					continue
				}
			}
		}

	}

	return
}
