package controller

import (
	"fmt"
	"strings"
	"sync"

	"be.ems/src/framework/i18n"
	"be.ems/src/framework/reqctx"
	"be.ems/src/framework/resp"
	"be.ems/src/framework/utils/parse"
	neFetchlink "be.ems/src/modules/ne/fetch_link"
	"be.ems/src/modules/ne/model"
	"be.ems/src/modules/ne/service"

	"github.com/gin-gonic/gin"
)

// 实例化控制层 NeInfoController 结构体
var NewNeInfo = &NeInfoController{
	neInfoService:    service.NewNeInfo,
	neLicenseService: service.NewNeLicense,
	neVersionService: service.NewNeVersion,
}

// 网元信息请求
//
// PATH /info
type NeInfoController struct {
	neInfoService    *service.NeInfo    // 网元信息服务
	neLicenseService *service.NeLicense // 网元授权激活信息服务
	neVersionService *service.NeVersion // 网元版本信息服务
}

// neStateCacheMap 网元状态缓存最后一次成功的信息
var neStateCacheMap sync.Map
var mutex sync.Mutex

// 网元信息状态
//
// GET /state
//
//	@Tags			ne
//	@Accept			json
//	@Produce		json
//	@Param			neType	query		string	true	"NE Type"	Enums(IMS,AMF,AUSF,UDM,SMF,PCF,NSSF,NRF,UPF,MME,CBC,OMC,SGWC,SMSC)
//	@Param			neId	query		string	true	"NE ID"		default(001)
//	@Success		200		{object}	object	"Response Results"
//	@Security		TokenAuth
//	@Summary		Network element information state
//	@Description	Network element information state
//	@Router			/ne/info/state [get]
func (s NeInfoController) State(c *gin.Context) {
	language := reqctx.AcceptLanguage(c)
	var querys struct {
		NeType string `form:"neType" binding:"required"`
		NeId   string `form:"neId" binding:"required"`
	}
	if err := c.ShouldBindQuery(&querys); err != nil {
		errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
		c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
		return
	}

	neInfo := s.neInfoService.FindByNeTypeAndNeID(querys.NeType, querys.NeId)
	if neInfo.NeId != querys.NeId || neInfo.IP == "" {
		c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
		return
	}
	neKey := fmt.Sprintf("%s_%s", neInfo.NeType, neInfo.NeId)

	// 网元直连
	resData, err := neFetchlink.NeState(neInfo)
	if err != nil {
		mutex.Lock()
		// 异常取上次缓存
		resDataCache, ok := neStateCacheMap.Load(neKey)
		if ok && resDataCache != nil {
			resDataCache.(map[string]any)["online"] = false
		} else {
			resDataCache = map[string]any{
				"online": false,
				"neId":   neInfo.NeId,
				"neName": neInfo.NeName,
				"neType": neInfo.NeType,
				"neIP":   neInfo.IP,
			}
		}
		neStateCacheMap.Store(neKey, resDataCache)
		mutex.Unlock()
		c.JSON(200, resp.OkData(resDataCache))
		return
	}

	// 存入缓存
	resData["online"] = true
	mutex.Lock()
	neStateCacheMap.Store(neKey, resData)
	mutex.Unlock()
	c.JSON(200, resp.OkData(resData))
}

// 网元neType和neID查询
//
// GET /byTypeAndID
//
//	@Tags			ne
//	@Accept			json
//	@Produce		json
//	@Param			neType	query		string	true	"NE Type"	Enums(IMS,AMF,AUSF,UDM,SMF,PCF,NSSF,NRF,UPF,MME,CBC,OMC,SGWC,SMSC)
//	@Param			neId	query		string	true	"NE ID"		default(001)
//	@Success		200		{object}	object	"Response Results"
//	@Security		TokenAuth
//	@Summary		Network element neType and neID queries
//	@Description	Network element neType and neID queries
//	@Router			/ne/info/byTypeAndID [get]
func (s NeInfoController) NeTypeAndID(c *gin.Context) {
	language := reqctx.AcceptLanguage(c)
	var querys struct {
		NeType string `form:"neType" binding:"required"`
		NeID   string `form:"neId" binding:"required"`
	}
	if err := c.ShouldBindQuery(&querys); err != nil {
		errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
		c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
		return
	}

	neInfo := s.neInfoService.FindByNeTypeAndNeID(querys.NeType, querys.NeID)
	if neInfo.NeId != querys.NeID || neInfo.IP == "" {
		c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
		return
	}
	c.JSON(200, resp.OkData(neInfo))
}

// 网元信息列表全部无分页
//
// GET /listAll
//
//	@Tags			ne
//	@Accept			json
//	@Produce		json
//	@Param			neType		query		string	true	"NE Type"
//	@Param			neId		query		string	true	"NE ID"	default(001)
//	@Param			bandStatus	query		boolean	true	"With status information"
//	@Param			bandHost	query		boolean	true	"With host information"
//	@Success		200			{object}	object	"Response Results"
//	@Security		TokenAuth
//	@Summary		The list of network element information is all unpaginated
//	@Description	The list of network element information is all unpaginated
//	@Router			/ne/info/listAll [get]
func (s NeInfoController) ListAll(c *gin.Context) {
	language := reqctx.AcceptLanguage(c)
	var querys struct {
		NeType     string `form:"neType"`
		NeId       string `form:"neId"`
		BandStatus bool   `form:"bandStatus"`
		BandHost   bool   `form:"bandHost"`
	}
	if err := c.ShouldBindQuery(&querys); err != nil {
		errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
		c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
		return
	}

	// 查询实体参数
	ne := model.NeInfo{}
	if querys.NeType != "" {
		ne.NeType = querys.NeType
	}
	if querys.NeId != "" {
		ne.NeId = querys.NeId
	}
	neList := s.neInfoService.Find(ne, querys.BandStatus, querys.BandHost)
	if len(neList) == 0 {
		c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
		return
	}
	c.JSON(200, resp.OkData(neList))
}

// 网元端Para5G配置文件读取
//
// GET /para5GFile
func (s NeInfoController) Para5GFileRead(c *gin.Context) {
	data, err := s.neInfoService.NeConfPara5GRead()
	if err != nil {
		c.JSON(200, resp.ErrMsg(err.Error()))
		return
	}
	c.JSON(200, resp.OkData(data))
}

// 网元端Para5G配置文件写入
//
// PUT /para5GFile
func (s NeInfoController) Para5GFileWrite(c *gin.Context) {
	var body struct {
		Content map[string]any `json:"content" binding:"required"` // 内容
		SyncNE  []string       `json:"syncNe"`                     // 同步到网元
	}
	if err := c.ShouldBindBodyWithJSON(&body); err != nil {
		errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
		c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
		return
	}

	err := s.neInfoService.NeConfPara5GWirte(body.Content, body.SyncNE)
	if err != nil {
		c.JSON(200, resp.ErrMsg(err.Error()))
		return
	}
	c.JSON(200, resp.Ok(nil))
}

// 网元端OAM配置文件读取
//
// GET /oamFile
func (s NeInfoController) OAMFileRead(c *gin.Context) {
	var querys struct {
		NeType string `form:"neType" binding:"required"`
		NeID   string `form:"neId" binding:"required"`
	}
	if err := c.ShouldBindQuery(&querys); err != nil {
		errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
		c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
		return
	}

	data, err := s.neInfoService.NeConfOAMReadSync(querys.NeType, querys.NeID)
	if err != nil {
		c.JSON(200, resp.ErrMsg(err.Error()))
		return
	}
	c.JSON(200, resp.OkData(data))
}

// 网元端OAM配置文件写入
//
// PUT /oamFile
func (s NeInfoController) OAMFileWrite(c *gin.Context) {
	language := reqctx.AcceptLanguage(c)
	var body struct {
		NeType  string         `json:"neType" binding:"required"`
		NeID    string         `json:"neId" binding:"required"`
		Content map[string]any `json:"content" binding:"required"` // 内容
		Sync    bool           `json:"sync"`                       // 同步到网元
	}
	if err := c.ShouldBindBodyWithJSON(&body); err != nil {
		errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
		c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
		return
	}

	// 查询网元获取IP
	neInfo := s.neInfoService.FindByNeTypeAndNeID(body.NeType, body.NeID)
	if neInfo.NeId != body.NeID || neInfo.IP == "" {
		c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
		return
	}

	err := s.neInfoService.NeConfOAMWirteSync(neInfo, body.Content, body.Sync)
	if err != nil {
		c.JSON(200, resp.ErrMsg(err.Error()))
		return
	}
	c.JSON(200, resp.Ok(nil))
}

// 网元信息列表
//
// GET /list
//
//	@Tags			ne
//	@Accept			json
//	@Produce		json
//	@Param			bandStatus	query		boolean	false	"The result carries the state of the network element"
//	@Param			neId		query		string	false	"NE ID"
//	@Param			neType		query		string	false	"Ne Type"
//	@Param			pageNum		query		number	true	"pageNum"	default(1)
//	@Param			pageSize	query		number	true	"pageSize"	default(10)
//	@Success		200			{object}	object	"Response Results"
//	@Security		TokenAuth
//	@Summary		Network element information list
//	@Description	Network element information list
//	@Router			/ne/info/list [get]
func (s NeInfoController) List(c *gin.Context) {
	query := reqctx.QueryMap(c)
	bandStatus := false
	if v, ok := query["bandStatus"]; ok {
		bandStatus = parse.Boolean(v)
	}
	rows, total := s.neInfoService.FindByPage(query, bandStatus)
	c.JSON(200, resp.OkData(map[string]any{"rows": rows, "total": total}))
}

// 网元信息
//
// GET /:id
//
//	@Tags			ne
//	@Accept			json
//	@Produce		json
//	@Param			value	path		string	true	"Row ID"
//	@Success		200		{object}	object	"Response Results"
//	@Security		TokenAuth
//	@Summary		Network element information
//	@Description	Network element information
//	@Router			/ne/info/{value} [get]
func (s NeInfoController) Info(c *gin.Context) {
	language := reqctx.AcceptLanguage(c)
	id := parse.Number(c.Param("id"))
	if id <= 0 {
		c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: id is empty"))
		return
	}

	neHost := s.neInfoService.FindById(id, true)
	if neHost.ID != id {
		// 没有可访问网元信息数据！
		c.JSON(200, resp.ErrMsg(i18n.TKey(language, "neInfo.noData")))
		return
	}

	c.JSON(200, resp.OkData(neHost))
}

// 网元信息新增
//
// POST /
//
//	@Tags			ne
//	@Accept			json
//	@Produce		json
//	@Param			data	body		object	true	"Request Param"
//	@Success		200		{object}	object	"Response Results"
//	@Security		TokenAuth
//	@Summary		Network element information addition
//	@Description	Network element information addition
//	@Router			/ne/info [post]
func (s NeInfoController) Add(c *gin.Context) {
	language := reqctx.AcceptLanguage(c)
	var body model.NeInfo
	err := c.ShouldBindBodyWithJSON(&body)
	if err != nil {
		errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
		c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
		return
	}
	if body.ID != 0 {
		c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: id not is empty"))
		return
	}

	// 检查属性值唯一
	uniqueInfo := s.neInfoService.CheckUniqueNeTypeAndNeId(body.NeType, body.NeId, 0)
	if !uniqueInfo {
		// 网元信息操作【%s】失败，同类型下标识已存在
		msg := i18n.TTemplate(language, "neInfo.errKeyExists", map[string]any{"key": body.NeId})
		c.JSON(200, resp.ErrMsg(msg))
		return
	}

	// 获取网元状态是否正常
	body.ServerState, err = neFetchlink.NeState(body)
	if err != nil {
		body.Status = 0
	} else {
		// 网元状态设置为在线
		body.Status = 1
		if parse.Boolean(body.ServerState["standby"]) {
			body.Status = 3
		}
		// 下发网管配置信息给网元
		if _, err = neFetchlink.NeConfigOMC(body); err != nil {
			body.Status = 2
		}
	}

	loginUserName := reqctx.LoginUserToUserName(c)
	// 新增Version信息
	neVersion := model.NeVersion{
		NeType:   body.NeType,
		NeId:     body.NeId,
		CreateBy: loginUserName,
	}
	// 新增License信息
	neLicense := model.NeLicense{
		NeType:   body.NeType,
		NeId:     body.NeId,
		CreateBy: loginUserName,
	}

	// 已有网元可获取的信息
	if body.ServerState != nil {
		if v, ok := body.ServerState["version"]; ok && v != nil {
			neVersion.Version = fmt.Sprint(v)
		}
		if v, ok := body.ServerState["sn"]; ok && v != nil {
			neLicense.SerialNum = fmt.Sprint(v)
		}
		if v, ok := body.ServerState["expire"]; ok && v != nil {
			neLicense.ExpiryDate = fmt.Sprint(v)
			neLicense.Status = "1"
		}
		if v, ok := body.ServerState["ueNumber"]; ok && v != nil {
			neLicense.UeNumber = parse.Number(v)
		}
		if v, ok := body.ServerState["nbNumber"]; ok && v != nil {
			neLicense.NbNumber = parse.Number(v)
		}
	}

	s.neVersionService.Insert(neVersion)
	s.neLicenseService.Insert(neLicense)
	body.CreateBy = loginUserName
	insertId := s.neInfoService.Insert(body)
	if insertId > 0 {
		c.JSON(200, resp.OkData(insertId))
		return
	}
	c.JSON(200, resp.Err(nil))
}

// 网元信息修改
//
// PUT /
//
//	@Tags			ne
//	@Accept			json
//	@Produce		json
//	@Param			data	body		object	true	"Request Param"
//	@Success		200		{object}	object	"Response Results"
//	@Security		TokenAuth
//	@Summary		Network element information modification
//	@Description	Network element information modification
//	@Router			/ne/info [put]
func (s NeInfoController) Edit(c *gin.Context) {
	language := reqctx.AcceptLanguage(c)
	var body model.NeInfo
	err := c.ShouldBindBodyWithJSON(&body)
	if err != nil {
		errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
		c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
		return
	}
	if body.ID <= 0 {
		c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: id is empty"))
		return
	}

	// 检查属性值唯一
	uniqueInfo := s.neInfoService.CheckUniqueNeTypeAndNeId(body.NeType, body.NeId, body.ID)
	if !uniqueInfo {
		// 网元信息操作【%s】失败，同类型下标识已存在
		msg := i18n.TTemplate(language, "neInfo.errKeyExists", map[string]any{"key": body.NeId})
		c.JSON(200, resp.ErrMsg(msg))
		return
	}

	// 检查是否存在
	neInfo := s.neInfoService.FindById(body.ID, false)
	if neInfo.ID != body.ID {
		// 没有可访问网元信息数据！
		c.JSON(200, resp.ErrMsg(i18n.TKey(language, "neInfo.noData")))
		return
	}
	// 赋予主机ID
	if neInfo.HostIDs != "" && len(body.Hosts) > 0 {
		hostIDs := strings.Split(neInfo.HostIDs, ",")
		for index, id := range hostIDs {
			body.Hosts[index].ID = parse.Number(id)
		}
	}

	// 获取网元状态是否正常
	body.ServerState, err = neFetchlink.NeState(neInfo)
	if err != nil {
		body.Status = 0
	} else {
		// 网元状态设置为在线
		body.Status = 1
		if parse.Boolean(body.ServerState["standby"]) {
			body.Status = 3
		}
		// 下发网管配置信息给网元
		if _, err = neFetchlink.NeConfigOMC(body); err != nil {
			body.Status = 2
		}
	}

	loginUserName := reqctx.LoginUserToUserName(c)
	neLicense := s.neLicenseService.FindByNeTypeAndNeID(neInfo.NeType, neInfo.NeId)
	neVersion := s.neVersionService.FindByNeTypeAndNeID(neInfo.NeType, neInfo.NeId)

	// 已有网元可获取的信息
	if body.ServerState != nil {
		if v, ok := body.ServerState["version"]; ok && v != nil {
			neVersion.Version = fmt.Sprint(v)
			neVersion.UpdateBy = loginUserName
		}
		if v, ok := body.ServerState["sn"]; ok && v != nil {
			neLicense.SerialNum = fmt.Sprint(v)
		}
		if v, ok := body.ServerState["expire"]; ok && v != nil {
			neLicense.ExpiryDate = fmt.Sprint(v)
			neLicense.Status = "1"
			neLicense.UpdateBy = loginUserName
		}
		if v, ok := body.ServerState["ueNumber"]; ok && v != nil {
			neLicense.UeNumber = parse.Number(v)
		}
		if v, ok := body.ServerState["nbNumber"]; ok && v != nil {
			neLicense.NbNumber = parse.Number(v)
		}
	}

	if neVersion.ID <= 0 {
		if neVersion.NeType != body.NeType || neVersion.NeId != body.NeId {
			neVersion.NeType = body.NeType
			neVersion.NeId = body.NeId
		}
		s.neVersionService.Update(neVersion)
	}
	if neLicense.ID <= 0 {
		if neLicense.NeType != body.NeType || neLicense.NeId != body.NeId {
			neLicense.NeType = body.NeType
			neLicense.NeId = body.NeId
		}
		s.neLicenseService.Update(neLicense)
	}

	body.UpdateBy = loginUserName
	rows := s.neInfoService.Update(body)
	if rows > 0 {
		c.JSON(200, resp.Ok(nil))
		return
	}
	c.JSON(200, resp.Err(nil))
}

// 网元信息删除
//
// DELETE /:id
//
//	@Tags			ne
//	@Accept			json
//	@Produce		json
//	@Param			value	path		string	true	"Row ID"
//	@Success		200		{object}	object	"Response Results"
//	@Security		TokenAuth
//	@Summary		Network element information deletion
//	@Description	Network element information deletion
//	@Router			/ne/info [delete]
func (s NeInfoController) Remove(c *gin.Context) {
	language := reqctx.AcceptLanguage(c)
	id := c.Param("id")
	if id == "" {
		c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: id is empty"))
		return
	}

	// 处理字符转id数组后去重
	uniqueIDs := parse.RemoveDuplicatesToArray(id, ",")
	// 转换成int64数组类型
	ids := make([]int64, 0)
	for _, v := range uniqueIDs {
		ids = append(ids, parse.Number(v))
	}

	rows, err := s.neInfoService.DeleteByIds(ids)
	if err != nil {
		c.JSON(200, resp.ErrMsg(i18n.TKey(language, err.Error())))
		return
	}
	msg := i18n.TTemplate(language, "app.common.deleteSuccess", map[string]any{"num": rows})
	c.JSON(200, resp.OkMsg(msg))
}
