// Author: NiuJiuRu
// Email: niujiuru@qq.com
// Date: 2025-11-20

package mcu_ctrl_board

import (
	"encoding/json"
	"fmt"
	"sync"
	"time"

	"hnyfkj.com.cn/rtu/linux/baseapp"
	"hnyfkj.com.cn/rtu/linux/netmgrd"
	"hnyfkj.com.cn/rtu/linux/utils/jsonrpc2"
)

const MODULE_NAME = "MCUCtrlBoard"

var (
	Board = &MCUCtrlBoard{
		OneEnvDataCh: make(chan *EnvSensorData, 1),
		ReqTakePhoCh: make(chan bool, 1),
		PwrWillOffCh: make(chan struct{}),
	}
)

// 定义控制板的组成结构
type MCUCtrlBoard struct {
	OneEnvDataCh chan *EnvSensorData // 单条环境数据
	ReqTakePhoCh chan bool           // 请求开始拍照
	PwrWillOffCh chan struct{}       // 通知即将掉电
}

// 定义传感器的数据结构
type EnvSensorData struct {
	NowTime     string `json:"nowtm"`       // 时间, 格式：YYYY-MM-DD HH:MM:SS
	Temperature string `json:"temperature"` // 温度, °C
	Humidity    string `json:"humidity"`    // 湿度, %RH
	WindSpeed   string `json:"wind_speed"`  // 风速, m/s
	WindDir     string `json:"wind_dir"`    // 风向, °
	Pressure    string `json:"pressure"`    // 大气压, hPa
	Voltage     string `json:"voltage"`     // 电压, V
}

// 将传感器数据字符串化
func (d EnvSensorData) String() string {
	return fmt.Sprintf("时间: %s, 温度: %s°C, 湿度: %s%%RH, 风速: %s米/秒, 风向: %s°, 大气压: %shPa, 电压: %sV",
		d.NowTime, d.Temperature, d.Humidity, d.WindSpeed, d.WindDir, d.Pressure, d.Voltage)
}

// 初始化控制板通信串口
func ModuleInit() bool {
	var ret int
	var err error

	for range 5 {
		if baseapp.IsExit1() {
			return false
		}
		ret, err = mcuCtrlBoard_ComInit()
		if ret == -1 {
			time.Sleep(1 * time.Second)
			continue
		} else {
			break
		}
	}
	if err != nil {
		baseapp.Logger.Errorf("[%s] 打开与控制板通信的串口失败: %v!!", MODULE_NAME, err)
	}

	err = loadCfgParams()
	if err != nil {
		baseapp.Logger.Warnf("[%s] 启动时读取控制板运行参数失败: %v!", MODULE_NAME, err)
	}

	return true
}

// 释放掉控制板通信串口
func ModuleExit() {
	mcuCtrlBoard_ComExit()
}

// 通知数据板稍后将掉电
func NotifyPwrWillOff() <-chan struct{} {
	return Board.PwrWillOffCh
}

// 控制板查询数据板状态
func (b *MCUCtrlBoard) getRTUStatus(r *jsonrpc2.Request) (*jsonrpc2.Response, error) {
	netst := "offline"
	if netmgrd.IsInetAvailable() {
		netst = "online"
	}

	systm := ""
	if netmgrd.IsSyncedNtpTime() {
		now := time.Now()
		systm = now.Format("2006-01-02 15:04:05")
	} else if r.Params != nil { // 同步控制板的系统时间
		var params struct {
			SystemTime string `json:"systm"`
		}
		if err := json.Unmarshal(r.Params, &params); err != nil {
			return jsonrpc2.BuildError(r, jsonrpc2.ErrInvalidParams, ""), nil
		}

		t, err := time.ParseInLocation("2006-01-02 15:04:05", params.SystemTime, time.Local)
		if err == nil {
			err = netmgrd.SetSystemTime(t)
		}
		if err != nil {
			baseapp.Logger.Warnf("同步控制板时间时有错误发生: %v!", err)
		}

		baseapp.Logger.Info("控制板时间已同步")
	}

	wrkst := "idle"
	if GlobalWorkState.Get() != Idle {
		wrkst = "busy"
	}

	wjson := fmt.Sprintf(`{"netst":"%s","systm":"%s","wrkst":"%s"}`, netst, systm, wrkst)
	return jsonrpc2.BuildResult(r, json.RawMessage(wjson))
}

// 控制板发送传感器数据
func (board *MCUCtrlBoard) sendSensorData(r *jsonrpc2.Request) (*jsonrpc2.Response, error) {
	GlobalWorkState.Add(SensorDataReceiving)
	defer GlobalWorkState.Remove(SensorDataReceiving)

	var dataOne EnvSensorData
	if err := json.Unmarshal([]byte(r.Params), &dataOne); err != nil {
		return jsonrpc2.BuildError(r, jsonrpc2.ErrInvalidParams, ""), nil
	}

	select {
	case board.OneEnvDataCh <- &dataOne:
	default:
		old := <-board.OneEnvDataCh // 弹出旧数据
		baseapp.Logger.Warnf("OneEnvData 通道满, 丢弃一条老数据: %s!", old.String())
		board.OneEnvDataCh <- &dataOne
	}

	return jsonrpc2.BuildResult(r, "success")
}

// 控制板请求数据板拍照
func (board *MCUCtrlBoard) takePhoto(r *jsonrpc2.Request) (*jsonrpc2.Response, error) {
	select {
	case board.ReqTakePhoCh <- true:
	default:
		<-board.ReqTakePhoCh // 弹出旧数据
		board.ReqTakePhoCh <- true
	}

	return jsonrpc2.BuildResult(r, "success")
}

// 控制板发送预掉电通知
func (board *MCUCtrlBoard) powerDown(r *jsonrpc2.Request) (*jsonrpc2.Response, error) {
	netst := "offline"
	if netmgrd.IsInetAvailable() {
		netst = "online"
	}

	systm := ""
	if netmgrd.IsSyncedNtpTime() {
		now := time.Now()
		systm = now.Format("2006-01-02 15:04:05")
	}

	wrkst := "idle"
	if GlobalWorkState.Get() != Idle {
		wrkst = "busy"
	} else {
		close(board.PwrWillOffCh)
	}

	wjson := fmt.Sprintf(`{"netst":"%s","systm":"%s","wrkst":"%s"}`, netst, systm, wrkst)

	return jsonrpc2.BuildResult(r, json.RawMessage(wjson))
}

var pendingRequests sync.Map // 存储所有待处理的请求ID和对应的应答通道

// 发送请求, 并等待应答
func (board *MCUCtrlBoard) sendRequest(req *jsonrpc2.Request, timeout int /*单位: ms*/) (*jsonrpc2.Response, error) {
	if req == nil || req.ID == nil {
		return nil, fmt.Errorf("invalid request or request ID")
	}

	id := *req.ID
	ch := make(chan *jsonrpc2.Response, 1)
	pendingRequests.Store(id, ch)
	defer pendingRequests.Delete(id)

	jsonStr, err := req.String()
	if err != nil {
		return nil, err
	}

	err = mcuCtrlBoard_SendCmd(jsonStr)
	if err != nil {
		return nil, err
	}

	timer := time.NewTimer(time.Duration(timeout) * time.Millisecond)
	defer timer.Stop()

	select {
	case resp := <-ch:
		return resp, nil
	case <-timer.C:
		return nil, fmt.Errorf("request %v timed out after %d ms", id, timeout)
	}
}

// 处理控制板返回的应答
func (board *MCUCtrlBoard) handleResponse(jsonStr string) error {
	w, err := jsonrpc2.ParseResponse(jsonStr)
	if err != nil {
		return fmt.Errorf("an error occurred while parsing JSON-RPC response: %v", err)
	}

	if w.ID == nil {
		return nil
	}

	id := *w.ID

	v, ok := pendingRequests.Load(id)
	if !ok {
		return fmt.Errorf("orphan response id=%d, no pending request", id)
	}

	ch, ok := v.(chan *jsonrpc2.Response)
	if !ok {
		return fmt.Errorf("invalid response channel for id=%d", id)
	}

	select {
	case ch <- w:
		return nil
	default:
		return fmt.Errorf("response dropped for id=%d, channel not receiving", id)
	}
}
