//
// Created by Carl.Guo on 2024/5/14.
//
#include "bpf_base.h"

#ifndef EUSPACES_APM_TRACE_H
#define EUSPACES_APM_TRACE_H

#define APM_REMOTE_ADDR_MAX_LEN 256

#define APM_TYPE_FROM_STRING_SIZE 2
#define APM_SAMPLE_STRING_SIZE 2
#define APM_HOST_ID_STRING_SIZE 16
#define APM_APP_ID_STRING_SIZE 16
#define APM_INSTANCE_ID_STRING_SIZE 16
#define APM_TRACE_ID_STRING_SIZE 32
#define APM_ASSUMED_APP_ID_STRING_SIZE 16
#define APM_SPAN_ID_STRING_SIZE 16

#define APM_TYPE_FROM_SIZE 1
#define APM_SAMPLE_SIZE 1
#define APM_HOST_ID_SIZE 8
#define APM_APP_ID_SIZE 8
#define APM_INSTANCE_ID_SIZE 8
#define APM_TRACE_ID_SIZE 16
#define APM_ASSUMED_APP_ID_SIZE 8
#define APM_SPAN_ID_SIZE 8

// cwtrace

#define CW_HEADER_KEY_LENGTH 7
#define CW_HEADER_KEY_VAL "cwtrace"
#define CW_HEADER_KEY_UFIRST_VAL "Cwtrace"
#define CW_HEADER_VAL_LENGTH 123
#define CW_HEADER_LENGTH 123
//#define CW_STREAM_HEADER_LEN 135 // CW_HEADER_KEY_LENGTH + 2 + CW_HEADER_VAL_LENGTH + 2 + 1
#define CW_STREAM_HEADER_LEN (CW_HEADER_KEY_LENGTH + 2 + CW_HEADER_VAL_LENGTH + 2 + 1)
#define MAX_HOSTNAME_SIZE 256

// cwother
// 格式：NN:ParentServiceName:MM[:ParentServiceSysTag]
// NN: 2位数字（ASCII），表示 ParentServiceName 的长度（0-32）
// MM: 2位数字（ASCII），表示 ParentServiceSysTag 的长度（0-32）
// 当 MM=00 时，格式为 NN:ParentServiceName:00（不包含最后的冒号和SysTag）
#define CW_SYS_HEADER_KEY_LENGTH 7
#define CW_SYS_HEADER_KEY_VAL "cwother"
#define CW_SYS_HEADER_KEY_UFIRST_VAL "Cwother"
#define CW_SYS_LEN_PREFIX_LENGTH 2  // 每个长度字段的长度（NN 或 MM）
#define CW_SYS_HEADER_VAL_LENGTH 76
#define CW_SYS_STREAM_HEADER_MAX_LEN (CW_SYS_HEADER_KEY_LENGTH + 2 + CW_SYS_HEADER_VAL_LENGTH + 2) // "cwother: " + val + "\r\n" = 87
#define CW_COMBINED_STREAM_MAX_LEN (CW_STREAM_HEADER_LEN - 1 + CW_SYS_STREAM_HEADER_MAX_LEN) // cwtrace(134) + cwother(87) = 221

#define MAX_MQ_TOPIC_SIZE 256  // Max MQ topic size (e.g., Kafka topic)
#define MAX_MQ_KEY_SIZE 256     // Max MQ key size (e.g., Kafka message key)

/***********************************************************
 * Trace Info Type Definitions
 * 定义 trace_info 的查找来源类型
 ***********************************************************/
#define APM_TRACE_INFO_TYPE_FIRST_FOUND     1  // 第一次从 trace_info_heap 中找到（通过 goid）
#define APM_TRACE_INFO_TYPE_REUSE_FOUND     2  // 从 goid_trace_info_heap 中复用找到（第二次或多次）
#define APM_TRACE_INFO_TYPE_THREAD_FOUND   3  // 从 thread_trace_info_heap 中找到（通过 tgid_pid）
#define APM_TRACE_INFO_TYPE_CTX_FOUND       4  // 从 thread_ctx 的 trace_key 中找到

/***********************************************************
 * Trace struct
 ***********************************************************/
struct apm_trace_key_t {
	__u32 tgid;
	__u32 pid;
	__u64 goid;
	__u64 connectid;
};

struct apm_sk_msg_key_t {
	__u32 tgid;
	__u32 remote_ip4 ;
	__u16 remote_port;
	__u16 local_port;
};

struct fd_trace_key_t {
	__u32 tgid;
	__u32 fd;
};

struct thread_trace_key_t {
	__u64 pid_tgid;
};

struct goid_trace_key_t {
	__u32 tgid;
	__u64 goid;
};

struct fd_trace_poll_times_t {
	__u32 start_count;
	__u32 end_count;
};

//struct apm_span_context {
//	unsigned char TraceID[APM_TRACE_ID_SIZE];
//	unsigned char SpanID[APM_SPAN_ID_SIZE];
//};

struct apm_span_context {
	unsigned char type_from[APM_TYPE_FROM_SIZE];
	unsigned char sample[APM_SAMPLE_SIZE];
	unsigned char host_id[APM_HOST_ID_SIZE];
	unsigned char app_id[APM_APP_ID_SIZE];
	unsigned char instance_id[APM_INSTANCE_ID_SIZE];
	unsigned char trace_id[APM_TRACE_ID_SIZE];
	unsigned char assumed_app_id[APM_ASSUMED_APP_ID_SIZE];
	unsigned char span_id[APM_SPAN_ID_SIZE];
	unsigned char sysvs[CW_SYS_HEADER_VAL_LENGTH];
};

// MQ 信息结构体（用于 Kafka、RabbitMQ 等消息队列）
struct mq_info_t {
	char topic[MAX_MQ_TOPIC_SIZE];
	char key[MAX_MQ_KEY_SIZE];
};

/*
	 * Whether traceID is zero ?
	 * For the client to actively send request, set traceID to zero.
	 */
//	bool is_trace_id_zero;
//	__u32 update_time; // 从系统开机开始到创建/更新时的间隔时间单位是秒
//	__u32 peer_fd;	   // 用于socket之间的关联
//	__u64 thread_trace_id; // 线程追踪ID
//	__u64 socket_id; // Records the socket associated when tracing was created (记录创建追踪时关联的socket)
struct apm_trace_info_t {
	__u64 trace_id;
	__u8 type;
	bool routine_reuse;
	struct apm_trace_key_t trace_key;
	struct fd_trace_key_t fd_trace_key;
	struct thread_trace_key_t thread_trace_key;
	struct goid_trace_key_t goid_trace_key;

//	struct apm_span_context psc;

//	struct apm_span_context sc;
};

// ---------- 业务上下文（thread_ctx） ----------
struct thread_ctx_t {
	__u64 token;         // 追踪 token / trace_id（入口处写入）
	__u64 ts_ns;         // 最近一次刷新时间
	__u64 exp_ns;        // 过期时间（now + TTL）
	__u32 root_thread;   // 主线程
	__u32 tgid;          // 所属进程
	__u32 parent_tid;    // 父线程（用于调试/回溯）
	__u8  is_main_thread;// 主线程
	__u16 level;         // 继承层数
	struct apm_trace_info_t *trace_info;
	struct apm_trace_key_t trace_key;
};

static __always_inline void cw_copy_byte_arrays(unsigned char *src, unsigned char *dst, __u32 size) {
//	for (int i = 0; i < size; i++) {
//		dst[i] = src[i];
//	}
	__builtin_memcpy(dst, src, size);
}
static __inline __u32 has_cw_header(const char *data);
static __always_inline void copy_byte_arrays(unsigned char *src, unsigned char *dst, __u32 size);
static __always_inline void generate_random_bytes(unsigned char *buff, __u32 size);
static __always_inline void hex_string_to_bytes(char *str, __u32 size, unsigned char *out);
static __always_inline void span_context_to_cw_string_stream(struct apm_span_context *ctx, char *buff, char type_from);

// 设置 trace 开始标记
// 用法: SET_TRACE_START(e, PROTOCOL_HTTP)
#define SET_TRACE_START(e, p) do { \
	(e)->trace_start = PROTOCOL_TRACE; \
	(e)->trace_end = 0; \
	(e)->protocol = (p); \
} while (0)

// 设置 trace 结束标记
// 用法: SET_TRACE_END(e, PROTOCOL_HTTP)
#define SET_TRACE_END(e, p) do { \
	(e)->trace_start = 0; \
	(e)->trace_end = PROTOCOL_TRACE; \
	(e)->protocol = (p); \
} while (0)

#define SET_TRACE_METHOD(e) do { \
	(e)->trace_start = 0; \
	(e)->trace_end = 0; \
} while (0)
static __inline __attribute__((__always_inline__))
struct apm_trace_info_t *get_apm_trace_info_by_trace_key(struct apm_trace_key_t trace_key);

#endif //EUSPACES_APM_TRACE_H
