package model

import (
	"encoding/json"
	"time"
)

const (
	ScopeKindCluster = "cluster"
)

type WafDetectionMessage struct {
	WafDetectionMessageBasic
	AttackedLog []WafDetectionAttackedLog `json:"attacked_log"`
	CreatedAt   int64                     `json:"created_at"`
}

type WafDetectionMessageBasic struct {
	ClusterKey string `json:"cluster_key"`
	Namespace  string `json:"namespace"`
	ResKind    string `json:"res_kind"`
	ResName    string `json:"res_name"`
	ServiceID  int64  `json:"service_id"`
	AppName    string `json:"app_name"`
}

type WafDetectionAttackedLog struct {
	ID             string `json:"id"`
	RuleID         int64  `json:"rule_id"`
	RuleName       string `json:"rule_name"`
	Action         string `json:"action"`
	AttackIP       string `json:"attack_ip"`
	AttackLoad     string `json:"attack_load"`
	AttackTime     int64  `json:"attack_time"`
	AttackType     string `json:"attack_type"`
	AttackedApp    string `json:"attacked_app"`
	AttackedURL    string `json:"attacked_url"`
	ReqPkg         string `json:"req_pkg"`
	RspPkg         string `json:"rsp_pkg,omitempty"`
	RspContentType string `json:"rsp_content_type,omitempty"`
}

type WafDetection struct {
	WafDetectionMessageBasic
	WafDetectionAttackedLog
	CreatedAt int64 `json:"created_at"`
}

type Event struct {
	ID           string                 `json:"id"`
	Type         string                 `json:"type"`         // 事件类型（关联类型）
	Description  string                 `json:"description"`  // 事件描述
	RuleKeys     []RuleKey              `json:"ruleKeys"`     // 该event涉及到的signals，触发的rule列表，去重
	Scopes       map[string][]Scope     `json:"scopes"`       // 关联后，需要保留每个signal的scope，去重
	Resources    []map[string]Scope     `json:"resources"`    // 资源列表，关联信号的所有scope，保留了scope内部的关系，去重
	Relation     Relation               `json:"relation"`     // 事件的关联表达，可能是图、时间轴
	Severity     int                    `json:"severity"`     // 严重程度 枚举；算法见下方
	Tags         []string               `json:"tags"`         // 事件标签，一期只有系统生成(规则子标签)，二期用户可自定义(标签系统)
	SignalsCount map[int]int            `json:"signalsCount"` // 关联的信号数量，按严重程度拆分
	UpdatedAt    int64                  `json:"updatedAt"`    // 更新时间
	CreatedAt    int64                  `json:"createdAt"`    // 创建时间
	Timestamp    time.Time              `json:"timestamp"`
	Context      map[string]interface{} `json:"context"` // 只有规则关联才有，取交集

	Process *Process `json:"process,omitempty"`
}

type Process struct {
	Status    int    `json:"status"`
	Processor string `json:"processor"`
	Remark    string `json:"remark"`
	Timestamp int64  `json:"timestamp"`
}

const (
	ProcessStatusUnProcessed      = 0
	ProcessStatusProcessed        = 1
	ProcessStatusOmitted          = 2
	ProcessStatusPendingProcessed = 3
)

type Relation struct {
	Type  string `json:"type"`            // 关系类型，可能是图、时间轴
	Graph *Graph `json:"graph,omitempty"` // 图
}

type Graph struct {
	Nodes map[string]*Node `json:"nodes"` // 节点，map类型用于快速确定node是否存在
	Edges []*Edge          `json:"edges"` // 边
}

type Node struct {
	ID         string                 `json:"id"`         // 根据规则生成，不同的关联方式会不同，如进程树可能是pid+pname
	Label      string                 `json:"label"`      // 节点标签，即类型，如：signal、process
	Properties map[string]interface{} `json:"properties"` // 其他信息
}

type Edge struct {
	Type        int                    `json:"type"`        // 边的类型，0-无向边，1-有向边。无向边时，Source Destination仅表示节点
	Relation    string                 `json:"relation"`    // 关系名称，如：父进程关系、网络调用关系、关联信号关系
	Source      *Node                  `json:"source"`      // 边的起点节点
	Destination *Node                  `json:"destination"` // 边的终点节点
	Properties  map[string]interface{} `json:"properties"`  // 其他信息
}

type AliasRuleKey RuleKey
type RuleKey struct {
	Version1 uint16 `json:"version1"`
	Name     string `json:"name"`
	Category string `json:"category"`
}

func (r RuleKey) MarshalJSON() ([]byte, error) {
	path := ""
	if r.Category != "" {
		path = r.Category
		if r.Name != "" {
			path = path + "/" + r.Name
		}
	}
	x := struct {
		AliasRuleKey
		Path string `json:"path"`
	}{AliasRuleKey(r), path}
	return json.Marshal(x)
}

func (r *RuleKey) GenKey() string {
	return r.Category + "$" + r.Name
}

type Scope struct {
	Kind string `json:"kind"` // required
	ID   string `json:"id"`   // optional，视具体情况
	Name string `json:"name"` // required
}

func (s *Scope) GenKey() string {
	return s.Kind + "$" + s.ID + "$" + s.Name
}

// GenSuggestionKey
// 集群以id+name去重，其他以name去重
func (s *Scope) GenSuggestionKey() string {
	if s.Kind == ScopeKindCluster {
		return s.Kind + "$" + s.ID + "$" + s.Name
	}
	return s.Kind + "$" + s.Name
}
