package netmgrd

import "C"

import (
	"sync"
	"sync/atomic"
	"time"

	"hnyfkj.com.cn/rtu/linux/baseapp"

	modem1 "hnyfkj.com.cn/rtu/linux/air720u" // 合宙4G调制解调器
	modem2 "hnyfkj.com.cn/rtu/linux/ec200u"  // 移远4G调制解调器
)

const MODULE_NAME = "NetworkManager"

var (
	isOnline        atomic.Bool  // 标记是否联网
	offlineStartTs  atomic.Int64 // 离线开始时间
	isSyncNTPTimeOK atomic.Bool  // 标记本地时间是否已同步成功
	curNetType      NetType      // 当前的网络类型: 有线、蜂窝
	mu1             sync.Mutex
	isRunning1      bool
	exitCh1         chan struct{}
	wg1             sync.WaitGroup
)

type NetType int

const (
	NetNone NetType = iota
	NetEth          // 有线网络, 注册网卡名为"eth0"
	NetLTE          // 蜂窝网络
)

func (n NetType) String() string {
	switch n {
	case NetEth:
		return "有线"
	case NetLTE:
		return "蜂窝"
	default:
		return "未知"
	}
}

const (
	interval1 = time.Duration(1) * time.Second
	interval2 = time.Duration(5) * time.Second
)

func ModuleInit() {
	go serviceRun()
}

// 联网保持服务
func serviceRun() {
	// 1, 首次打开网络
	openNetwork()

	// 2, 监控联网状态
	t := time.NewTimer(interval1)
	defer t.Stop()
	for {
		select {
		case <-t.C:
			// 3.1 切换网络-看情况
			eth0CableOK, _ := isEth0CableConnected()
			if eth0CableOK && curNetType != NetEth { // 有线插入 && 当前不是有线
				baseapp.Logger.Warnf("[%s] 检测到有线接入，切换到有线网络...", MODULE_NAME)
				openNetwork()
			} else if !eth0CableOK && curNetType == NetEth { // 有线拔出 && 当前还是有线
				baseapp.Logger.Warnf("[%s] 检测到有线断开，切换到蜂窝网络...", MODULE_NAME)
				openNetwork()
			}

			// 3.2, 联网检测-看结果
			dnsOK, pingOK, tcpOK, httpOK := CheckNetwork()
			baseapp.Logger.Infof("[%s] 联网类型: %s; 检测结果: DNS OK=%v, PING OK=%v, TCP OK=%v, HTTP OK=%v", MODULE_NAME, curNetType.String(), dnsOK, pingOK, tcpOK, httpOK)

			// 3.3, 联网成功-在线时
			if dnsOK && pingOK && tcpOK {
				isOnline.Store(true)
				offlineStartTs.Store(0)

				if isSyncNTPTimeOK.Load() {
					t.Reset(interval2)
					continue
				}

				err := SyncNTPTime()
				if err == nil {
					isSyncNTPTimeOK.Store(true)
					baseapp.Logger.Infof("[%s] NTP时间已同步", MODULE_NAME)
					t.Reset(interval2)
					continue
				} else {
					baseapp.Logger.Errorf("[%s] 同步NTP时间时有错误发生: %v!!", MODULE_NAME, err)
					t.Reset(interval1)
					continue
				}
			}

			// 3.4, 联网失败-离线时
			if isOnline.Load() { // 状态由"1"变为"0"
				isOnline.Store(false)
				offlineStartTs.Store(time.Now().UnixNano()) // 记录离线开始时间
			}

			if offlineDuration() >= (time.Duration(60) * time.Second) {
				baseapp.Logger.Warnf("[%s] 网络长时间的断开, 尝试重新激活...", MODULE_NAME)
				switch curModemType {
				case Air720U: //重启合宙4G调制解调器
					modem1.ModuleExit()
					modem1.ModuleInit(true)
				case EC200U: // 重启移远4G调制解调器
					modem2.ModuleExit()
					modem2.ModuleInit(true)
				}
				openNetwork()
				offlineStartTs.Store(time.Now().UnixNano()) // 重置离线开始时间
			}

			t.Reset(interval1)
		case <-baseapp.IsExit2():
			return
		} // select end
	} // for end
}

// 返回联网状态
func IsInetAvailable() bool {
	return isOnline.Load()
}

// 时间是否同步
func IsSyncedNtpTime() bool {
	return isSyncNTPTimeOK.Load()
}

// 等待所有成功
func WaitAllOK(timeout time.Duration) bool {
	deadline := time.Now().Add(timeout)
	tick := 50 * time.Millisecond

	for {
		if IsInetAvailable() && IsSyncedNtpTime() {
			return true
		}

		remaining := time.Until(deadline)
		if remaining <= 0 {
			return false
		}

		sleep := min(tick, remaining)
		time.Sleep(sleep)
	}
}

// 返回断网时长
func offlineDuration() time.Duration {
	if IsInetAvailable() {
		return 0
	}
	ts := offlineStartTs.Load()
	if ts == 0 {
		return 0
	}
	return time.Since(time.Unix(0, ts))
}

// 打开有线网络
func openEth0Net() bool {
	mu1.Lock()
	defer mu1.Unlock()

	if isRunning1 {
		return true
	}

	killAllUdhcpc()
	err := disable4GInterfaces()
	if err != nil {
		baseapp.Logger.Errorf("[%s] 错误: %v!!", MODULE_NAME, err)
		return false
	}

	bExists, _ := udhcpcEth0Exists()
	if bExists {
		killEth0Udhcpc()
	}

	err = dialupEth0()
	if err != nil {
		baseapp.Logger.Errorf("[%s] 拨号连接\"eth0\"时发生错误: %v!!", MODULE_NAME, err)
		return false
	}
	ipv4, mask, err := getEth0Addr()
	if err != nil {
		baseapp.Logger.Errorf("[%s] 读取\"eth0\"地址时发生错误: %v!!", MODULE_NAME, err)
		return false
	}
	baseapp.Logger.Infof("[%s] \"eth0\"分配的地址: %s/%s", MODULE_NAME, ipv4, mask)

	exitCh1 = make(chan struct{})
	wg1.Add(1)
	go func() { // 启动携程守护"eth0"网卡上的 "udhcpc"后台服务进程
		defer wg1.Done()
		monitorEth0Udhcpc(exitCh1)
	}()

	isRunning1 = true
	return isRunning1
}

// 断开有线网络
func closeEth0Net() {
	mu1.Lock()
	defer mu1.Unlock()

	if !isRunning1 {
		return
	}

	close(exitCh1)
	wg1.Wait() // 等待守护"eth0"网卡上的 "udhcpc"后台服务进程的携程退出

	bExists, _ := udhcpcEth0Exists()
	if bExists {
		killEth0Udhcpc()
	}

	isRunning1 = false
}

// 打开连接网络
func openNetwork() {
	closeEth0Net()
	switch curModemType {
	case Air720U: //合宙4G调制解调器
		modem1.Stop4GNetwork()
	case EC200U: // 移远4G调制解调器
		modem2.Stop4GNetwork()
	}

	eth0CableOK, _ := isEth0CableConnected()
	if eth0CableOK && openEth0Net() {
		curNetType = NetEth
		baseapp.Logger.Infof("[%s] ✅ 有线网络已连接", MODULE_NAME)
		return
	}

	start4GNetwork := func() bool {
		startOK := false
		switch curModemType {
		case Air720U: //合宙4G调制解调器
			if eth2CableOK, _ := modem1.Is4GCableConnected(); eth2CableOK {
				startOK = modem1.Start4GNetwork()
				time.Sleep(time.Duration(500) * time.Millisecond)
				enableEth0() // 恢复有线网口
			}
		case EC200U: // 移远4G调制解调器
			if usb0CableOK, _ := modem2.Is4GCableConnected(); usb0CableOK {
				startOK = modem2.Start4GNetwork()
				time.Sleep(time.Duration(500) * time.Millisecond)
				enableEth0() // 恢复有线网口
			}
		}
		return startOK
	}

	if start4GNetwork() {
		curNetType = NetLTE
		baseapp.Logger.Infof("[%s] ✅ 蜂窝网络已连接(%s)", MODULE_NAME, curModemType.String())
		return
	}

	curNetType = NetNone
	baseapp.Logger.Warnf("[%s] 当前无可用网络接口(有线/蜂窝均不可用)!", MODULE_NAME)
}

// 得到当前联网类型: 有线、蜂窝
func GetCurrentNetType() NetType {
	return curNetType
}

//export RTU_IsInetAvailable
func RTU_IsInetAvailable() C.int {
	if IsInetAvailable() {
		return 1
	}
	return 0
}

//export RTU_IsSyncedNtpTime
func RTU_IsSyncedNtpTime() C.int {
	if IsSyncedNtpTime() {
		return 1
	}
	return 0
}
