package containers

import (
	"fmt"
	"github.com/coroot/coroot-node-agent/flags"
	"github.com/coroot/coroot-node-agent/utils"
	. "github.com/coroot/coroot-node-agent/utils/modelse"
	klog "github.com/sirupsen/logrus"
	"time"
)

func (c *Container) RegisterAppInfo(r *Registry, pid uint32) error {
	if *flags.Test {
		c.AppInfo.AppName = c.WhiteSettingInfo.AppName
		c.AppInfo.AppIdHash.IntVal, _ = utils.BuildInt64ID(c.WhiteSettingInfo.AppName).ToInt64()
		c.AppInfo.AppIdHash.HashtVal = utils.BuildInt64ID(c.WhiteSettingInfo.AppName).ToHashByte()
		c.AppInfo.CodeType = CodeTypeJava
		c.AppInfo.SetAppSuccess()
		return nil
	}
	if r.isFusing {
		return fmt.Errorf("euspace in fusing can not to regist app")
	}
	if c.WhiteSettingInfo.AppName == "" {
		return fmt.Errorf("appname is empty.")
	}
	var err error
	originAppName := c.AppInfo.AppName
	originAppId := c.AppInfo.AppIdHash.IntVal
	originInstanceId := c.AppInfo.InstanceIdHash.IntVal
	whiteAppName := c.WhiteSettingInfo.AppName
	reRegFlag := c.checkReRegTime(RegisterAppInterval)
	if originAppName != whiteAppName || reRegFlag {
		cl := "first "
		if reRegFlag {
			cl = "re "
		}
		c.AppInfo.CodeType = c.GetCodeTypeFromCache(pid)
		if c.AppInfo.CodeType.IsUnknownCode() || c.AppInfo.CodeType.IsWaitCheck() {
			return fmt.Errorf("[%sregister app] Unknown app code[%s] .", cl, c.AppInfo.CodeType.String())
		}
		c.AppInfo.AppIdHash.IntVal, err = utils.BuildInt64ID(whiteAppName).ToInt64()
		c.AppInfo.AppIdHash.HashtVal = utils.BuildInt64ID(whiteAppName).ToHashByte()
		if err != nil {
			return err
		}
		c.AppInfo.ServiceType = c.AppInfo.CodeType.ServiceTypeString()
		// 注册
		nodeInfo := r.nodeInfo.GetNodeInfo()
		if nodeInfo == nil {
			return fmt.Errorf("[%sregister app] Unknown node info.", cl)
		}
		// if reRegFlag {
		c.ReBuildIds(pid)
		// }
		registerAppReq := RegisterAppReq{
			AppId:       c.AppInfo.AppIdHash.IntVal,
			AppName:     c.WhiteSettingInfo.AppName,
			AccountId:   nodeInfo.AccountID,
			HostId:      nodeInfo.HostID,
			AgentId:     c.AppInfo.AgentId,
			Sn:          c.AppInfo.Sn,
			Sport:       c.AppInfo.Sport,
			ServiceType: c.AppInfo.ServiceType,
			CodeType:    c.AppInfo.CodeType.Int(),
			App_type:    1,
			AppLang:     "ebpf",
			Sys:         nodeInfo.SysTag,
		}
		//klog.Infof("[%sregister app] Register App req: %s.", cl, registerAppReq.String())
		klog.Infof("[%sregister app] Register App", cl)
		err = r.connServer.RegisterApp(registerAppReq)
		if err != nil {
			klog.WithError(err).Errorf("[%sregister app] Failed Register App %s.", cl, registerAppReq.String())
			return err
		}

		c.AppInfo.RegisterAt = time.Now().Unix()
		c.AppInfo.AppName = c.WhiteSettingInfo.AppName

		// reset kernel
		if c.Isl7AttachSuccess() {
			if (originAppId != c.AppInfo.AppIdHash.IntVal && originAppId != 0) ||
				(originInstanceId != c.AppInfo.InstanceIdHash.IntVal && originInstanceId != 0) {
				klog.Infoln("[kprobe] reset kernel proc_info.")
				err = r.tracer.InitKProcInfo(pid, &c.AppInfo)
				if err != nil {
					klog.WithError(err).Errorf("[kprobe] Failed reset KProcInfo.")
					return err
				}
				c.AppInfo.UpdateAt = time.Now().Unix()
			}
		}
	}
	c.AppInfo.SetAppSuccess()
	return nil
}

func (c *Container) checkReRegTime(duration time.Duration) bool {
	if c.AppInfo.RegisterAt != 0 {
		elapsed := time.Since(time.Unix(c.AppInfo.RegisterAt, 0))
		return elapsed > duration
	}
	return false
}
