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 (
	eth0LinkDegraded atomic.Bool  // 当eth0网卡无法上网时标记降级
	isOnline         atomic.Bool  // 标记是否联网: true 或 false
	offlineStartTime time.Time    // 离线开始时间, 不依赖系统时钟
	enableTimeSync   atomic.Bool  // 是否启用时间同步(默认: 启用)
	isSyncNTPTimeOK  atomic.Bool  // 标记系统的时间是否已同步成功
	lastSyncNTPTime  time.Time    // 记录同步时间, 为下次同步准备
	curNetType       atomic.Int32 // 当前联网类型: "有线"、"蜂窝"
	mu1              sync.Mutex
	isRunning1       bool
	exitCh1          chan struct{}
	wg1              sync.WaitGroup
)

type NetType int32

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

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

func setNetType(n NetType) {
	curNetType.Store(int32(n))
}

func getNetType() NetType {
	return NetType(curNetType.Load())
}

func init() {
	enableTimeSync.Store(true) // 默认开启时间同步
}

func SetTimeSyncEnabled(enable bool) {
	enableTimeSync.Store(enable)
}

const (
	interval1          = time.Duration(1) * time.Second
	interval2          = time.Duration(3) * time.Second
	eth0ManagementAddr = "192.168.90.1/24"
)

func ModuleInit() {
	offlineStartTime = time.Now()
	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 { // 检测到eth0的网线拔出后, 清除降级标记
				eth0LinkDegraded.CompareAndSwap(true, false)
			}

			if eth0CableOK && getNetType() != NetEth && !eth0LinkDegraded.Load() { /////////// 有线插入 && 当前不是有线 && 有线还未降级
				baseapp.Logger.Warnf("[%s] 检测到有线插入，正在尝试切换到有线网络...", MODULE_NAME)
				openNetwork()
			} else if (!eth0CableOK || eth0LinkDegraded.Load()) && getNetType() == NetEth { // (有线拔出 || 有线已降级) && 当前还是有线
				baseapp.Logger.Warnf("[%s] 检测到有线断网，正在尝试切换到蜂窝网络...", MODULE_NAME)
				openNetwork()
			}

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

			// 3.3, 联网成功-在线时
			netOK := tcpOK || httpOK
			if netOK {
				isOnline.Store(true)

				if !enableTimeSync.Load() { // 时间同步功能被禁用, 下面不再同步
					isSyncNTPTimeOK.Store(false)
					t.Reset(interval2)
					continue
				}

				if isSyncNTPTimeOK.Load() && time.Since(lastSyncNTPTime) < (time.Duration(60)*time.Minute) {
					t.Reset(interval2)
					continue
				}

				var err error
				if !httpTime.IsZero() { // 优先使用HTTP时间, 实测速度快且精度高
					err = SetSystemTime(httpTime)
				}

				if httpTime.IsZero() || err != nil {
					err = SyncNTPTime() //// 同步HTTP时间失败, 则尝试同步标准时间
				}

				if err == nil {
					isSyncNTPTimeOK.Store(true)
					baseapp.Logger.Infof("[%s] ✅ 系统时间已同步: %s", MODULE_NAME, time.Now().Format("2006-01-02 15:04:05"))
					lastSyncNTPTime = time.Now()
					t.Reset(interval2)
					continue
				} else {
					isSyncNTPTimeOK.Store(false)
					baseapp.Logger.Errorf("[%s] 同步系统时间时有错误发生: %v!!", MODULE_NAME, err)
					t.Reset(interval1)
					continue
				}
			}

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

			if time.Since(offlineStartTime) >= (time.Duration(20)*time.Second) &&
				getNetType() == NetEth && !eth0LinkDegraded.Load() { // eth0无法联网

				offlineDur := time.Since(offlineStartTime).Round(time.Second)
				baseapp.Logger.Warnf(
					"[%s] eth0链路正常但持续无法访问外网(%v), 标记eth0为Degraded, 后续联网优先级将切换至蜂窝！",
					MODULE_NAME,
					offlineDur,
				)

				eth0LinkDegraded.Store(true) // 开始设置eth0网卡降级使用

				if err := SetupEth0ForManagement(eth0ManagementAddr); err != nil {
					baseapp.Logger.Errorf("[%s] 设置eth0管理地址失败: %v", MODULE_NAME, err)
				} else {
					baseapp.Logger.Infof("[%s] eth0已切换为管理口模式(%s)", MODULE_NAME, eth0ManagementAddr)
				}
			}

			if time.Since(offlineStartTime) >= (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()
				offlineStartTime = time.Now() // 重置离线开始时间
			}

			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() {
			if !enableTimeSync.Load() || IsSyncedNtpTime() {
				return true
			}
		}

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

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

// 打开有线网络
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 && !eth0LinkDegraded.Load() { // 有线插入 && 有线未降级
		_ = openEth0Net()
		setNetType(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() {
		setNetType(NetLTE)
		baseapp.Logger.Infof("[%s] ✅ 蜂窝网络已激活(%s)", MODULE_NAME, curModemType.String())
		return
	}

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

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

//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
}
