package ne_alarm_state_check_cmd

import (
	"encoding/json"
	"fmt"
	"runtime"
	"sort"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/tsmask/go-oam"

	"be.ems/src/framework/constants"
	"be.ems/src/framework/cron"
	"be.ems/src/framework/logger"
	"be.ems/src/framework/utils/parse"
	neModel "be.ems/src/modules/ne/model"
	neService "be.ems/src/modules/ne/service"
	neDataModel "be.ems/src/modules/ne_data/model"
	neDataService "be.ems/src/modules/ne_data/service"
	oamService "be.ems/src/modules/oam/service"
	wsService "be.ems/src/modules/ws/service"
)

var (
	triggerMax    int64         = 3                // 阈值：连续触发次数大于该值才会产生告警
	triggerCount  sync.Map                         // 阈值连续触发次数，存储每个事件的触发记录
	triggerWindow time.Duration = 30 * time.Second // 事件触发的时间窗口
)

var NewProcessor = &NeAlarmStateCheckCMDProcessor{
	neInfoService:  neService.NewNeInfo,
	neStateService: neDataService.NewNEState,
	wsSendService:  wsService.NewWSSend,
	count:          0,
}

// NeAlarmStateCheckCMDProcessor 网元告警内存/CPU/磁盘检查
type NeAlarmStateCheckCMDProcessor struct {
	neInfoService  *neService.NeInfo      // 网元信息服务
	neStateService *neDataService.NEState // 网元状态信息服务
	wsSendService  *wsService.WSSend      // ws发送服务
	count          int                    // 执行次数
}

// alarmParams 告警参数
type alarmParams struct {
	AlarmTitle        string `json:"alarmTitle"`        // NE State Check Alarm CPU/Memory/Disk
	AlarmType         string `json:"alarmType"`         // EquipmentAlarm=2
	OrigSeverity      string `json:"origSeverity"`      // Major=2
	SpecificProblem   string `json:"specificProblem"`   // Alarm Cause: CPU/Memory/Disk status received from target NE reaches the threshold
	SpecificProblemID string `json:"specificProblemId"` // AC10100
	AddInfo           string `json:"addInfo"`           // 告警补充信息
	CPUUseGt          int64  `json:"cpuUseGt"`          // CPU使用率大于， 范围0~100*CPU核心数
	MemUseGt          int64  `json:"memUseGt"`          // 内存使用率大于， 范围0~100%
	DiskUseGt         int64  `json:"diskUseGt"`         // 磁盘使用率大于， 范围0~100%

	// === 非参数字段 ===
	AlarmId string // 告警ID
}

func (s *NeAlarmStateCheckCMDProcessor) Execute(data any) (any, error) {
	s.count++ // 执行次数加一
	options := data.(cron.JobData)
	sysJob := options.SysJob
	logger.Infof("重复:%v 任务ID:%d  执行次数:%d", options.Repeat, sysJob.JobId, s.count)
	// 返回结果，用于记录执行结果
	result := map[string]any{
		"count": s.count,
	}

	// 读取参数值
	var params alarmParams
	err := json.Unmarshal([]byte(sysJob.TargetParams), &params)
	if err != nil {
		return nil, fmt.Errorf("json params err: %v", err)
	}
	// 检查使用率
	numCPU := runtime.NumCPU()
	if params.CPUUseGt > int64(numCPU*100) || params.CPUUseGt < 0 {
		return nil, fmt.Errorf("cpuUseGt must be between 0 and 100 * NumCPU")
	}
	if params.MemUseGt > 100 || params.MemUseGt < 0 {
		return nil, fmt.Errorf("memUseGt must be between 0 and 100")
	}
	if params.DiskUseGt > 100 || params.DiskUseGt < 0 {
		return nil, fmt.Errorf("diskUseGt must be between 0 and 100")
	}

	neList := s.neInfoService.Find(neModel.NeInfo{}, true, false)
	for _, neInfo := range neList {
		if neInfo.CreateTime == 0 {
			continue
		}

		// 网元在线状态
		isOnline := parse.Boolean(neInfo.ServerState["online"])
		if !isOnline {
			continue
		}

		// 检查状态
		sysCpuUsage, sysMemUsage, sysDiskUsage := s.serverState(neInfo.ServerState)
		// 检查CPU/Memory/Disk使用率
		warnMsg := []string{}
		if int64(sysCpuUsage) >= params.CPUUseGt {
			warnMsg = append(warnMsg, fmt.Sprintf("cpu usage %.2f%%", sysCpuUsage))
		}
		if int64(sysMemUsage) >= params.MemUseGt {
			warnMsg = append(warnMsg, fmt.Sprintf("memory usage %.2f%%", sysMemUsage))
		}
		if int64(sysDiskUsage) >= params.DiskUseGt {
			warnMsg = append(warnMsg, fmt.Sprintf("disk usage %.2f%%", sysDiskUsage))
		}
		var err error
		if len(warnMsg) > 0 {
			currentTime := time.Now()
			validTimes := []time.Time{}
			if v, ok := triggerCount.Load(neInfo.RmUID); ok {
				times := v.([]time.Time)
				// 清理过期的记录：10秒前的触发记录不再计入
				for _, t := range times {
					if currentTime.Sub(t) <= triggerWindow {
						validTimes = append(validTimes, t)
					}
				}
				validTimes = append(validTimes, currentTime)
				triggerCount.Store(neInfo.RmUID, validTimes)
			} else {
				// 事件第一次触发，初始化记录
				validTimes = append(validTimes, currentTime)
				triggerCount.Store(neInfo.RmUID, validTimes)
			}
			if int64(len(validTimes)) >= triggerMax {
				err = fmt.Errorf("greater than %s", strings.Join(warnMsg, ", "))
			}
		}

		// 检查状态连续触发
		if err == nil {
			continue
		}
		addInfo := params.AddInfo
		if addInfo != "" {
			addInfo = addInfo + ", " + err.Error()
		} else {
			addInfo = err.Error()
		}

		// 事件产生时间
		alarmTime := time.Now().UnixMilli()
		// 告警ID
		params.AlarmId = fmt.Sprintf("%d%d", constants.ALARM_CMD_CHECK, alarmTime)
		// 创建告警
		alarm := oam.Alarm{
			NeUid:             neInfo.RmUID,                    // 网元唯一标识
			AlarmTime:         alarmTime,                       // 事件产生时间
			AlarmId:           params.AlarmId,                  // 告警ID 唯一，清除时对应
			AlarmCode:         constants.ALARM_CMD_CHECK,       // 告警状态码
			AlarmType:         params.AlarmType,                // 告警类型
			AlarmTitle:        params.AlarmTitle,               // 告警标题
			PerceivedSeverity: params.OrigSeverity,             // 告警级别
			AlarmStatus:       oam.ALARM_STATUS_ACTIVE,         // 告警状态
			SpecificProblem:   params.SpecificProblem,          // 告警问题原因
			SpecificProblemID: params.SpecificProblemID,        // 告警问题原因ID
			AddInfo:           addInfo,                         // 告警辅助信息
			LocationInfo:      "NE CPU/Memory/Disk: Heartbeat", // 告警定位信息
		}
		if err = oamService.NewAlarm.Resolve(alarm); err == nil {
			result[neInfo.RmUID] = "cmd alarm"
		}
		triggerCount.Delete(neInfo.RmUID)
	}

	// 返回结果，用于记录执行结果
	return result, nil
}

// serverState 网元状态记录
func (s NeAlarmStateCheckCMDProcessor) serverState(state map[string]any) (float64, float64, float64) {
	// 网元CPU使用率
	var nfCpuUsage float64 = 0
	// CPU使用率
	var sysCpuUsage float64 = 0
	if state["cpu"] != nil {
		cpu := state["cpu"].(map[string]any)
		v := parse.Number(cpu["sysCpuUsage"])
		sysCpuUsage = float64(v) / 100
		nfv := parse.Number(cpu["nfCpuUsage"])
		nfCpuUsage = float64(nfv) / 100
	}

	// 网元内存使用KB
	var nfMemUsed int64 = 0
	// 内存使用率
	var sysMemUsage float64 = 0
	if state["mem"] != nil {
		mem := state["mem"].(map[string]any)
		v := parse.Number(mem["sysMemUsage"])
		sysMemUsage = float64(v) / 100
		nfMemUsed = parse.Number(mem["nfUsedMem"])
	}

	// 磁盘使用率
	var sysDiskUsage float64 = 0
	if state["disk"] != nil {
		mem := state["disk"].(map[string]any)
		disks := mem["partitionInfo"].([]any)
		sort.Slice(disks, func(i, j int) bool {
			iUsed := parse.Number(disks[i].(map[string]any)["used"])
			jUsed := parse.Number(disks[j].(map[string]any)["used"])
			return iUsed > jUsed
		})
		disk := disks[0].(map[string]any)
		total := parse.Number(disk["total"])
		used := parse.Number(disk["used"])
		sysDiskUsage = (float64(used) / float64(total)) * 100
		sysDiskUsage, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", sysDiskUsage), 64)
	}

	// 插入网元状态记录
	neState := neDataModel.NEState{
		NeType:       fmt.Sprint(state["neType"]),
		NeId:         fmt.Sprint(state["neId"]),
		Version:      fmt.Sprint(state["version"]),
		Capability:   parse.Number(state["capability"]),
		SerialNum:    fmt.Sprint(state["sn"]),
		ExpiryDate:   fmt.Sprint(state["expire"]),
		SysCpuUsage:  sysCpuUsage,
		SysMemUsage:  sysMemUsage,
		SysDiskUsage: sysDiskUsage,
		NfCpuUsage:   nfCpuUsage,
		NfMemUsed:    nfMemUsed,
		CreateTime:   parse.Number(state["refreshTime"]),
	}
	s.neStateService.Insert(neState)
	// 删除网元状态记录7天前
	ltTime := time.Now().AddDate(0, 0, -7).UnixMilli()
	s.neStateService.DeleteByTime(ltTime)
	// 推送ws消息
	groupID := fmt.Sprintf("%s_%s_%s", wsService.GROUP_NE_STATE, neState.NeType, neState.NeId)
	s.wsSendService.ByGroupID(groupID, neState)

	return sysCpuUsage, sysMemUsage, sysDiskUsage
}
