//
// Created by Carl.Guo on 2024/4/1.
//

struct {
	__uint(type, BPF_MAP_TYPE_LRU_HASH);
	__type(key, __u32);
	__type(value, struct thread_ctx_t);
	__uint(max_entries, 65535);
} thread_ctx_map SEC(".maps");


struct {
	__uint(type, BPF_MAP_TYPE_LRU_HASH);
	__type(key, struct fd_trace_key_t);
	__type(value, struct fd_trace_poll_times_t);
	__uint(max_entries, 65535);
} l7_request_fd_pool_map SEC(".maps");

struct {
	__uint(type, BPF_MAP_TYPE_LRU_HASH);
	__uint(key_size, sizeof(struct apm_trace_key_t));
	__uint(value_size, sizeof(struct apm_span_context));
	__uint(max_entries, 32768);
} apm_parent_span_context_map SEC(".maps");

struct {
	__uint(type, BPF_MAP_TYPE_LRU_HASH);
	__uint(key_size, sizeof(struct apm_trace_key_t));
	__uint(value_size, sizeof(struct apm_span_context));
	__uint(max_entries, 32768);
} apm_current_span_context_map SEC(".maps");

struct {
	__uint(type, BPF_MAP_TYPE_LRU_HASH);
	__uint(key_size, sizeof(struct apm_sk_msg_key_t));
	__uint(value_size, sizeof(struct apm_span_context));
	__uint(max_entries, 32768);
} apm_current_span_context_by_ipport_map SEC(".maps");

struct {
	__uint(type, BPF_MAP_TYPE_LRU_HASH);
	__uint(key_size, sizeof(struct apm_trace_key_t));
	__uint(value_size, sizeof(struct apm_trace_info_t));
	__uint(max_entries, 32768);
} trace_info_heap SEC(".maps");

struct {
	__uint(type, BPF_MAP_TYPE_LRU_HASH);
	__uint(key_size, sizeof(struct fd_trace_key_t));
	__uint(value_size, sizeof(struct apm_trace_info_t));
	__uint(max_entries, 32768);
} fd_trace_info_heap SEC(".maps");

struct {
	__uint(type, BPF_MAP_TYPE_LRU_HASH);
	__uint(key_size, sizeof(struct thread_trace_key_t));
	__uint(value_size, sizeof(struct apm_trace_info_t));
	__uint(max_entries, 32768);
} thread_trace_info_heap SEC(".maps");

struct {
	__uint(type, BPF_MAP_TYPE_LRU_HASH);
	__uint(key_size, sizeof(struct goid_trace_key_t));
	__uint(value_size, sizeof(struct apm_trace_info_t));
	__uint(max_entries, 32768);
} goid_trace_info_heap SEC(".maps");

struct {
	__uint(type, BPF_MAP_TYPE_HASH);
	__uint(key_size, sizeof(__u64));
	__uint(value_size, sizeof(__u32));
	__uint(max_entries, 32768);
} trace_event_count_heap SEC(".maps");

struct pid_of_connection_ptr_key_t {
	__u64 num;
	__u64 connection_ptr;
};

struct {
	__uint(type, BPF_MAP_TYPE_HASH);
	__uint(key_size, sizeof(__u64));
	__uint(value_size, sizeof(struct pid_of_connection_ptr_key_t));
	__uint(max_entries, 10240);
} pid_of_connection_ptr_maps SEC(".maps");

//struct {
//	__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
//	__uint(key_size, sizeof(__u32));
//	__uint(value_size, sizeof(struct apm_span_context));
//	__uint(max_entries, 1);
//} parent_span_context_storage_map SEC(".maps");

struct {
	__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
	__uint(key_size, sizeof(__u32));
	__uint(value_size, sizeof(struct apm_span_context));
	__uint(max_entries, 1);
} cw_parent_span_context_storage_map SEC(".maps");

struct {
	__uint(type, BPF_MAP_TYPE_HASH);
	__uint(key_size, sizeof(__u16));
	__uint(value_size, sizeof(__u8));
	__uint(max_entries, 64);
} l4_header_code_types SEC(".maps");

#define MAX_LEN 1022
#define L7_IOVEC_BUF_SIZE 1024
#define MAX_L7_IOVEC_BUF_SIZE 10240

struct sock_t {
	__u32 size;
	__u32 header_offset_idx;
	__u32 host_offset_idx;
	__u32 end_str_len;
	void * payload_char_p;
	void * payload_len_p;
	char payload[MAX_LEN];
	char header_stream[CW_COMBINED_STREAM_MAX_LEN + 1]; // cwtrace + cwother + '\0'
	char host[MAX_HOSTNAME_SIZE];
	struct ebpf_proc_info* proc_info;
};

struct {
	__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
	__type(key, __u32);
	__type(value, struct sock_t);
	__uint(max_entries, 1);
} socket_heap SEC(".maps");

struct {
	__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
	__type(key, int);
	__type(value, struct apm_span_context);
	__uint(max_entries, 1);
} apm_span_context_heap SEC(".maps");

static __inline __attribute__((__always_inline__))
struct apm_trace_key_t get_apm_trace_key(__u64 timeout, bool is_socket_io) {
	__u64 pid_tgid = bpf_get_current_pid_tgid();
	__u64 goid = 0;

	if (timeout) {
		goid = get_rw_goid(timeout * NS_PER_SEC, is_socket_io);
	}

	struct apm_trace_key_t key = {};

	key.tgid = (__u32) (pid_tgid >> 32);

//	struct ebpf_proc_info *info = bpf_map_lookup_elem(&proc_info_map, &key.tgid);
//	if (info && info->code_type == 1005) {
//		// dotnet 使用 connectid 作为 Key，该 key 维护在 pid_of_connection_ptr_maps 中
//		cw_bpf_debug("[Go] [uprobe/ent]: proc_info_map::%ld, %d, %d\n", info->code_type);
	// 解决4.x问题
	struct pid_of_connection_ptr_key_t *e = bpf_map_lookup_elem(&pid_of_connection_ptr_maps, &key.tgid);
	if (e) {
		cw_bpf_debug("[Go] [uprobeThread/get_apm_trace_key]getget: rdi_ptr::pid:%d, %llx\n", key.tgid, e->connection_ptr);
		key.connectid = e->connection_ptr;
	}
//		} else {
//			cw_bpf_debug("[Go] [uprobeThread/get_apm_trace_key]getget: rdi_ptr::pid:%d\n", key.tgid);
//		}
//	} else {
	// 其他语言使用 trace_id 作为 Key
	if (goid) {
		key.goid = goid;
	} else {
		key.pid = (__u32) pid_tgid;
	}
//	}

//    debug("key.tgid:%llu|%llu",key.tgid,key.goid);
//    debug("apm key.pid:%d",(__u32)pid_tgid);
//    debug("apm key.goid:%llu",key.goid);
//    cw_bpf_debug("[Trace ID] thread id:%d",(__u32)pid_tgid);
//	bpf_printk("[get_apm_trace_key] pid:[%d]|GOID:[%llu]", (__u32) pid_tgid, key.goid);
	return key;
}

static __inline __attribute__((__always_inline__))
struct thread_trace_key_t get_thread_trace_key(__u64 id) {
	struct thread_trace_key_t trace_key = {};
	trace_key.pid_tgid = id;
	return trace_key;
}

static __inline __attribute__((__always_inline__))
__u64 get_apm_trace_id(__u32 pid, __u32 tid) {
	struct apm_trace_key_t trace_key = get_apm_trace_key(120 * NS_PER_SEC, true);

	struct apm_trace_info_t *trace_info = bpf_map_lookup_elem(&trace_info_heap, &trace_key);
	if (trace_info) {
		cw_bpf_debug("info_trace_id:%llu", trace_info->trace_id);
		return trace_info->trace_id;
	}
	return 0;
}

//	find Parent from go_ancerstor_by_runq_map and find in  go_ancerstor_map == 0
//	find by tgid_pid == 0
//	find by tgid_goid == 0
static __inline __attribute__((__always_inline__))
struct apm_trace_info_t *get_apm_trace_info_v2(struct apm_trace_key_t trace_key, __u32 tgid, __u32 pid) {
//	struct apm_trace_key_t trace_key = get_apm_trace_key(120 * NS_PER_SEC, true);
//	struct apm_trace_info_t *trace_info = bpf_map_lookup_elem(&trace_info_heap, &trace_key);
//	if (trace_info) {
////		bpf_printk("info_trace_id:%llu", trace_info->trace_id);
//		return trace_info;
//	}

	__u64 goid = trace_key.goid;
	struct go_key key = {.tgid = tgid, .goid = goid};

	//	find Parent from go_ancerstor_by_runq_map and find in  go_ancerstor_map == 0
	__u64 *runq_map_goid = bpf_map_lookup_elem(&go_ancerstor_by_runq_map, &key);
	if (runq_map_goid) {
//			bpf_printk("-----[Kernel Enter][HTTP]:has 1 runq_map_goid1 :%llu", *runq_map_goid);
		struct go_key runq_map_goid_key = {.tgid = tgid, .goid = *runq_map_goid};
//			bpf_printk("-----[Kernel Enter][HTTP]: only one in go_ancerstor_by_runq_map. Now find it from go_ancerstor_map");
		//	find Parent from go_ancerstor_map
		__u64 *ancestor_goid = bpf_map_lookup_elem(&go_ancerstor_map, &runq_map_goid_key);
		if (ancestor_goid) {
//				bpf_printk("-----[Kernel Enter][HTTP]:has a newancestor  in go_ancerstor_map :%llu", *newancestor3);
			struct apm_trace_key_t trace_key2 = {.tgid = tgid, .goid = *ancestor_goid};
			struct apm_trace_info_t *trace_info = bpf_map_lookup_elem(&trace_info_heap, &trace_key2);
			if (trace_info) {
//				bpf_printk("[get_apm_trace_info_v2] [find goid in go_ancerstor_map] [key:%d-%llu] -->%llu", tgid, goid,trace_info->trace_id);

//				struct goid_trace_key_t k = {.tgid = tgid, .goid = get_current_goroutine()};
				// 祖先协程被复用
				if (trace_info->routine_reuse == true) {
//					bpf_printk("[get_apm_trace_info_v2] [routine_reuse already set] [key:%d-%llu] -->%llu", tgid, goid,	trace_info->trace_id);
					return NULL;
				}
				if (trace_info->routine_reuse == false) {
//						trace_id = trace_info->trace_id;
					trace_info->routine_reuse = true;
//						bpf_map_update_elem(&trace_info_heap, &key, trace_info, BPF_EXIST);
//					bpf_printk("[sssset routine_reuse true] [key:%d-%llu] -->%llu", tgid, goid, trace_info->trace_id);
					return trace_info;
				}
			}
		}
//			 todo 保存 gocache
//			trace_id = get_trace_id_from_runq_map(tgid, goid);
	}
//	}

	return NULL;
}

static __inline __attribute__((__always_inline__))
struct apm_trace_info_t *
get_apm_trace_info_v3(struct apm_trace_key_t trace_key, __u64 tgid_pid, __u32 tgid, __u32 pid) {
	struct apm_trace_info_t *trace_info = get_apm_trace_info_v2(trace_key, tgid, pid);
	struct goid_trace_key_t key_goid = {.tgid = tgid, .goid = trace_key.goid};

	if (trace_info != NULL) {
		trace_info->type = 1;
//		    trace_info = get_apm_trace_info_v2(id, pid, tid);
//		trace_id = trace_info->trace_id;
		trace_info->goid_trace_key = key_goid;
		// [save] [goid_trace_key_t => trace_info]  (goid_trace_info_heap)]
		// 保存goid -> trace数据
		bpf_map_update_elem(&goid_trace_info_heap, &key_goid, trace_info, BPF_ANY);
//		    if (trace_info!=NULL)
//		    bpf_printk("%llu",trace_info->trace_id);
//	    bpf_printk("[get_apm_trace_info_v3 save] [key:%d-%llu] -> trace_id:%llu",key_goid.tgid,key_goid.goid ,trace_info->trace_id);
	}

	if (trace_info == NULL) {
//		bpf_printk("[get_apm_trace_info_v3]  find by goid_trace_info_heap2 ");
		// Second or multiple times
		// [find] [goid_trace_key => tmp_trace_info] = [apm_trace_info_t (goid_trace_info_heap)]
		struct apm_trace_info_t *tmp_goid_trace_info = bpf_map_lookup_elem(&goid_trace_info_heap, &key_goid);
		if (tmp_goid_trace_info != NULL) {
//		    trace_id = *ttt;
//			bpf_printk(" [get_apm_trace_info_v3 find ooooooooooook] [key:%d-%llu] -> trace_id:%llu", key_goid.tgid,key_goid.goid, tmp_goid_trace_info->trace_id);
			// todo do not use
			tmp_goid_trace_info->goid_trace_key = key_goid;

			// [find] [tmp_trace_info.apm_trace_key => trace_info] = [apm_trace_info_t (trace_info_heap)]
			trace_info = bpf_map_lookup_elem(&trace_info_heap, &tmp_goid_trace_info->trace_key);
			if (trace_info) {
				// 将key保存在trace_info用于后续清除
				trace_info->goid_trace_key = key_goid;
				// Second or multiple times
				trace_info->type = 2;
			}
		}
	}

	if (trace_info == NULL) {
//		bpf_printk("[get_apm_trace_info_v3] find by tgid_pid");
		struct thread_trace_key_t t_key = get_thread_trace_key(tgid_pid);
		trace_info = bpf_map_lookup_elem(&thread_trace_info_heap, &t_key);
		if (trace_info != NULL) {
//			bpf_printk("ttttttttttttt trace_id:%llu", trace_info->trace_id);
			trace_info->type = 3;
		}
	}
	return trace_info;
}

static __inline __attribute__((__always_inline__))
struct apm_trace_info_t *get_apm_trace_info_by_trace_key(struct apm_trace_key_t trace_key) {
	struct apm_trace_info_t *trace_info = bpf_map_lookup_elem(&trace_info_heap, &trace_key);
	if (trace_info) {
		return trace_info;
	}
	return NULL;
}

static __inline __attribute__((__always_inline__))
struct apm_trace_info_t *get_apm_trace_info(__u32 pid, __u32 tid) {
	struct apm_trace_key_t trace_key = get_apm_trace_key(120 * NS_PER_SEC, true);
	struct apm_trace_info_t *trace_info = bpf_map_lookup_elem(&trace_info_heap, &trace_key);
	if (trace_info) {
		return trace_info;
	}
	return NULL;
}

static __inline __attribute__((__always_inline__))
struct fd_trace_key_t get_fd_trace_key(__u32 pid, __u64 fd) {
	struct fd_trace_key_t trace_key = {};
	trace_key.tgid = pid;
	trace_key.fd = fd;
	return trace_key;
}

static __inline __attribute__((__always_inline__))
__u64 get_fd_trace_id(__u32 pid, __u32 fd) {
	struct fd_trace_key_t trace_key = get_fd_trace_key(pid, fd);
	struct apm_trace_info_t *trace_info = bpf_map_lookup_elem(&fd_trace_info_heap, &trace_key);
	if (trace_info) {
		cw_bpf_debug("fd_trace_id:%llu", trace_info->trace_id);
		return trace_info->trace_id;
	}
	return 0;
}

static __inline __attribute__((__always_inline__))
struct apm_trace_info_t *get_trace_info_by_fd(__u32 pid, __u32 fd) {
	struct fd_trace_key_t trace_key = get_fd_trace_key(pid, fd);
	struct apm_trace_info_t *trace_info = bpf_map_lookup_elem(&fd_trace_info_heap, &trace_key);
	if (trace_info) {
		return trace_info;
	}
	return NULL;
}

static __inline __attribute__((__always_inline__))
void cw_save_parent_tracking_span(struct apm_span_context *sc) {
	struct apm_trace_key_t trace_key = get_apm_trace_key(120 * NS_PER_SEC, true);
//	__u64 pid_tgid = bpf_get_current_pid_tgid();
//	cw_bpf_debug("[pid:%d][goid:%d] save psc header", (__u32) (pid_tgid >> 32), trace_key.goid);
//	for (int i = 0; i < APM_APP_ID_SIZE; i++) {
//		cw_bpf_debug("trace_enter_write - span_id_from = %02x", sc->app_id[i]);
//	}
	long err = bpf_map_update_elem(&apm_parent_span_context_map, &trace_key, sc, BPF_ANY);
	if (err != 0) {
		cw_bpf_debug("Failed to update tracked_spans map: %ld", err);
		return;
	}
}

static __inline __attribute__((__always_inline__))
struct apm_span_context *cw_get_parent_tracking_span() {
	struct apm_trace_key_t trace_key = get_apm_trace_key(120 * NS_PER_SEC, true);
	struct apm_span_context *apm_sc = {0};
	struct apm_span_context *span_contexts = bpf_map_lookup_elem(&apm_parent_span_context_map, &trace_key);
//	bpf_printk("-------");

	if (span_contexts) {
		/*for (int i = 0; i < APM_TYPE_FROM_SIZE; i++) {
			bpf_printk("type_from[%d] = %02x", i, span_contexts->type_from[i]);
		}
		for (int i = 0; i < APM_SAMPLE_SIZE; i++) {
			bpf_printk("sample[%d] = %02x", i, span_contexts->sample[i]);
		}
		for (int i = 0; i < APM_HOST_ID_SIZE; i++) {
			bpf_printk("host_id[%d] = %02x", i, span_contexts->host_id[i]);
		}
		for (int i = 0; i < APM_APP_ID_SIZE; i++) {
			bpf_printk("app_id[%d] = %02x", i, span_contexts->app_id[i]);
		}
		for (int i = 0; i < APM_INSTANCE_ID_SIZE; i++) {
			bpf_printk("instance_id[%d] = %02x", i, span_contexts->instance_id[i]);
		}
		for (int i = 0; i < APM_TRACE_ID_SIZE; i++) {
			bpf_printk("trace_id[%d] = %02x", i, span_contexts->trace_id[i]);
		}
		for (int i = 0; i < APM_ASSUMED_APP_ID_SIZE; i++) {
			bpf_printk("assumed_app_id[%d] = %02x", i, span_contexts->assumed_app_id[i]);
		}
		for (int i = 0; i < APM_SPAN_ID_SIZE; i++) {
			bpf_printk("span_id[%d] = %02x", i, span_contexts->span_id[i]);
		}*/
		apm_sc = span_contexts;
	}
//	bpf_printk("-------end");

	return apm_sc;
}

static __inline __attribute__((__always_inline__))
struct apm_span_context *cw_get_parent_tracking_span_by_trace_key(struct apm_trace_key_t trace_key) {
	struct apm_span_context *apm_sc = {0};
	struct apm_span_context *span_contexts = bpf_map_lookup_elem(&apm_parent_span_context_map, &trace_key);
	if (span_contexts) {
		apm_sc = span_contexts;
	}
	return apm_sc;
}

static __inline __attribute__((__always_inline__))
__u64 clear_parent_span_context() {
	struct apm_trace_key_t trace_key = get_apm_trace_key(120 * NS_PER_SEC, true);
	bpf_map_delete_elem(&apm_parent_span_context_map, &trace_key);
	return 0;
}

static __inline __attribute__((__always_inline__))
__u64 clear_parent_span_context_by_trace_key(struct apm_trace_key_t trace_key) {
	bpf_map_delete_elem(&apm_parent_span_context_map, &trace_key);
	return 0;
}

static __inline __attribute__((__always_inline__))
__u64 clear_current_span_context() {
	struct apm_trace_key_t trace_key = get_apm_trace_key(120 * NS_PER_SEC, true);
	bpf_map_delete_elem(&apm_current_span_context_map, &trace_key);
	return 0;
}

static __inline __attribute__((__always_inline__))
__u64 cw_clear_trace(__u32 tgid, __u32 pid, __u32 fd) {
	struct apm_trace_key_t trace_key = get_apm_trace_key(120 * NS_PER_SEC, true);
	struct fd_trace_key_t fd_trace_key = get_fd_trace_key(tgid, fd);
	// 清除 trace_info_heap
	struct apm_trace_info_t *trace_info = bpf_map_lookup_elem(&trace_info_heap, &trace_key);
	if (trace_info) {
		bpf_map_delete_elem(&thread_trace_info_heap, &trace_info->thread_trace_key);
		// 清除 goid_trace_info_heap
		bpf_map_delete_elem(&goid_trace_info_heap, &trace_info->goid_trace_key);
//		bpf_printk("clean goid_trace_info_heap ok %d", trace_info->goid_trace_key.goid);
	}
	// 清除trace信息
	bpf_map_delete_elem(&trace_info_heap, &trace_key);
	bpf_map_delete_elem(&fd_trace_info_heap, &fd_trace_key);
	bpf_map_delete_elem(&apm_parent_span_context_map, &trace_key);
	return 0;
}

// Client当前sc
static __inline __attribute__((__always_inline__))
void cw_save_current_tracking_span(struct apm_span_context *sc) {
	struct apm_trace_key_t trace_key = get_apm_trace_key(120 * NS_PER_SEC, true);
//	bpf_printk("[save cw sc]%d",trace_key.goid);
	bpf_map_update_elem(&apm_current_span_context_map, &trace_key, sc, BPF_ANY);
}


static __inline __attribute__((__always_inline__))
struct apm_span_context *cw_get_current_tracking_span(struct apm_trace_info_t *trace_info) {
	struct apm_trace_key_t trace_key = {0};
	if (trace_info){
		trace_key = trace_info->trace_key;
	}
//	bpf_printk("[get cw sc]%d",trace_key.goid);
//	bpf_printk("[get cw sc2]%d",trace_info->trace_key.goid);

	struct apm_span_context *apm_sc = {0};
	struct apm_span_context *span_contexts = bpf_map_lookup_elem(&apm_current_span_context_map, &trace_key);
//	bpf_printk("-------");

	if (span_contexts == NULL && trace_info) {
		if (trace_info->routine_reuse == true) {
//			bpf_printk("[get cw sc bbb] :%llu", trace_info->trace_key.goid);
			struct apm_trace_key_t ancestor_trace_key = trace_info->trace_key;
			span_contexts = bpf_map_lookup_elem(&apm_current_span_context_map, &ancestor_trace_key);
		}
	}

	if (span_contexts) {
		/*for (int i = 0; i < APM_TYPE_FROM_SIZE; i++) {
			bpf_printk("cw_get_current_tracking_span-type_from[%d] = %02x", i, span_contexts->type_from[i]);
		}
		for (int i = 0; i < APM_SAMPLE_SIZE; i++) {
			bpf_printk("cw_get_current_tracking_span-sample[%d] = %02x", i, span_contexts->sample[i]);
		}
		for (int i = 0; i < APM_HOST_ID_SIZE; i++) {
			bpf_printk("cw_get_current_tracking_span-host_id[%d] = %02x", i, span_contexts->host_id[i]);
		}
		for (int i = 0; i < APM_APP_ID_SIZE; i++) {
			bpf_printk("cw_get_current_tracking_span-app_id[%d] = %02x", i, span_contexts->app_id[i]);
		}
		for (int i = 0; i < APM_INSTANCE_ID_SIZE; i++) {
			bpf_printk("cw_get_current_tracking_span-instance_id[%d] = %02x", i, span_contexts->instance_id[i]);
		}
		for (int i = 0; i < APM_TRACE_ID_SIZE; i++) {
			bpf_printk("cw_get_current_tracking_span-trace_id[%d] = %02x", i, span_contexts->trace_id[i]);
		}
		for (int i = 0; i < APM_ASSUMED_APP_ID_SIZE; i++) {
			bpf_printk("cw_get_current_tracking_span-assumed_app_id[%d] = %02x", i, span_contexts->assumed_app_id[i]);
		}
		for (int i = 0; i < APM_SPAN_ID_SIZE; i++) {
			bpf_printk("cw_get_current_tracking_span-span_id[%d] = %02x", i, span_contexts->span_id[i]);
		}*/
		apm_sc = span_contexts;
	}
//	bpf_printk("-------end");

	return apm_sc;
}


static __inline __attribute__((__always_inline__))
void cw_save_current_span_context_by_ipport(__u32 remote_ip4, __u16 remote_port, __u16 local_port, struct apm_span_context *sc) {
	__u64 pid_tgid = bpf_get_current_pid_tgid();
	struct apm_sk_msg_key_t sk_msg_key = {};
	sk_msg_key.tgid = (__u32) (pid_tgid >> 32);
	sk_msg_key.remote_ip4 = remote_ip4;
	sk_msg_key.remote_port = remote_port;
	sk_msg_key.local_port = local_port;
	bpf_map_update_elem(&apm_current_span_context_by_ipport_map, &sk_msg_key, sc, BPF_ANY);
}

static __inline __attribute__((__always_inline__))
struct apm_span_context *cw_get_current_span_context_by_ipport(__u32 remote_ip4, __u16 remote_port, __u16 local_port) {
	struct apm_span_context *apm_sc = {0};
	__u64 pid_tgid = bpf_get_current_pid_tgid();
	struct apm_sk_msg_key_t sk_msg_key = {};
	sk_msg_key.tgid = (__u32) (pid_tgid >> 32);
	sk_msg_key.remote_ip4 = remote_ip4;
	sk_msg_key.remote_port = remote_port;
	sk_msg_key.local_port = local_port;
//	bpf_printk("sk_msg_key.remote_ip4 [%llu]",sk_msg_key.remote_ip4);
//	bpf_printk("sk_msg_key.remote_port [%llu]",sk_msg_key.remote_port);
	struct apm_span_context *span_contexts = bpf_map_lookup_elem(&apm_current_span_context_by_ipport_map, &sk_msg_key);
	if (span_contexts) {
		apm_sc = span_contexts;
//		for (int i = 0; i < APM_ASSUMED_APP_ID_SIZE; i++) {
//			bpf_printk("cw_get_current_tracking_span-assumed_app_id[%d] = %02x", i, span_contexts->assumed_app_id[i]);
//		}
	}
	return apm_sc;
}

static __inline __attribute__((__always_inline__))
void cw_clean_current_span_context_by_ipport(__u32 remote_ip4, __u16 remote_port, __u16 local_port, __u32 tgid) {
	struct apm_sk_msg_key_t sk_msg_key = {};
	sk_msg_key.tgid = tgid;
	sk_msg_key.remote_ip4 = remote_ip4;
	sk_msg_key.remote_port = remote_port;
	sk_msg_key.local_port = local_port;
	bpf_map_delete_elem(&apm_current_span_context_by_ipport_map, &sk_msg_key);
}

static __inline __attribute__((__always_inline__))
__u32 cw_add_event_count(__u64 trace_id) {
	__u32 *event_count = bpf_map_lookup_elem(&trace_event_count_heap, &trace_id);
	if (event_count != NULL) {
		*event_count = *event_count + 1;
		return *event_count;
	}
	return 0;
}

static __inline __attribute__((__always_inline__))
__u32 cw_get_event_count(__u64 trace_id) {
	__u32 *event_count = bpf_map_lookup_elem(&trace_event_count_heap, &trace_id);
	if (event_count != NULL) {
		return *event_count;
	}
	return 0;
}

static __inline __attribute__((__always_inline__))
struct apm_trace_info_t cw_save_trace_info(__u64 id, __u32 pid, __u64 fd) {
	// apm trace
//	struct apm_trace_key_t trace_key = {0};
//	trace_key = get_apm_trace_key(120 * NS_PER_SEC, true);

	// fd trace
//	struct fd_trace_key_t fd_trace_key = {0};
//	fd_trace_key = get_fd_trace_key(pid, fd);

	// trace info
	struct apm_trace_info_t trace_info = {0};
	__u64 uid_base = bpf_ktime_get_ns();
	trace_info.trace_id = bpf_get_current_pid_tgid() + uid_base;
	// apm trace
	trace_info.trace_key = get_apm_trace_key(120 * NS_PER_SEC, true);
	// fd trace
	trace_info.fd_trace_key = get_fd_trace_key(pid, fd);
	// thread trace
	trace_info.thread_trace_key = get_thread_trace_key(id);

	//	入口方法缓存
	bpf_map_update_elem(&trace_info_heap, &trace_info.trace_key, &trace_info, BPF_NOEXIST);
	bpf_map_update_elem(&fd_trace_info_heap, &trace_info.fd_trace_key, &trace_info, BPF_NOEXIST);
	bpf_map_update_elem(&thread_trace_info_heap, &trace_info.thread_trace_key, &trace_info, BPF_NOEXIST);


//	struct goid_trace_key_t key = {.tgid = id, .goid = get_current_goroutine()};
//	bpf_map_update_elem(&goid_trace_info_heap, &key, &trace_info, BPF_NOEXIST);


	// 事件个数
	__u32 event_count = 0;
	bpf_map_update_elem(&trace_event_count_heap, &trace_info.trace_id, &event_count, BPF_NOEXIST);
	return trace_info;
}

/* 直接从 ip_net (u32 network order) + port_field (u32 raw msg->remote_port)
 * 提取高16位 port（network order），并直接生成 8 字节 每字节 0..9 的 assumed_app_id_out
 */
static __always_inline void ipport_to_16digits_from_u32_high(__u32 ip_net, __u32 port_field, unsigned char out[16]) {
	// 1) 提取 port 高 16 位（network-order），和 ip 的 4 字节（network-order）
	__u16 port_net_high = (__u16)((port_field >> 16) & 0xffff);

	__u8 b0 = (ip_net >> 24) & 0xFF;
	__u8 b1 = (ip_net >> 16) & 0xFF;
	__u8 b2 = (ip_net >> 8) & 0xFF;
	__u8 b3 = (ip_net) & 0xFF;
	__u8 p0 = (port_net_high >> 8) & 0xFF;
	__u8 p1 = (port_net_high) & 0xFF;

	// 2) 两轮 FNV-1a：h1 和 h2（h2 用不同种子/tweak），各自产出 8 字节，共 16 字节 raw
	uint64_t h1 = 14695981039346656037ULL; // FNV offset basis
#pragma clang loop unroll(full)
	for (int i = 0; i < 6; i++) {
		__u8 v = (i==0)?b0: (i==1)?b1: (i==2)?b2: (i==3)?b3: (i==4)?p0: p1;
		h1 ^= (uint64_t)v;
		h1 *= (uint64_t)1099511628211ULL;
	}
	uint64_t h2 = 14695981039346656037ULL ^ 0x9e3779b97f4a7c15ULL; // tweak seed
#pragma clang loop unroll(full)
	for (int i = 0; i < 6; i++) {
		__u8 v = (i==0)?b0: (i==1)?b1: (i==2)?b2: (i==3)?b3: (i==4)?p0: p1;
		h2 ^= (uint64_t)v;
		h2 *= (uint64_t)1099511628211ULL;
	}

	__u8 raw[16];
	// h1 -> raw[0..7] (big-endian)
	raw[0] = (h1 >> 56) & 0xFF;
	raw[1] = (h1 >> 48) & 0xFF;
	raw[2] = (h1 >> 40) & 0xFF;
	raw[3] = (h1 >> 32) & 0xFF;
	raw[4] = (h1 >> 24) & 0xFF;
	raw[5] = (h1 >> 16) & 0xFF;
	raw[6] = (h1 >> 8) & 0xFF;
	raw[7] = (h1) & 0xFF;
	// h2 -> raw[8..15] (big-endian)
	raw[8]  = (h2 >> 56) & 0xFF;
	raw[9]  = (h2 >> 48) & 0xFF;
	raw[10] = (h2 >> 40) & 0xFF;
	raw[11] = (h2 >> 32) & 0xFF;
	raw[12] = (h2 >> 24) & 0xFF;
	raw[13] = (h2 >> 16) & 0xFF;
	raw[14] = (h2 >> 8) & 0xFF;
	raw[15] = (h2) & 0xFF;

	// 3) 把每个 raw byte 映射到 0..9（用 mod10_u8 不用除法）
#pragma clang loop unroll(full)
	for (int i = 0; i < 16; i++) {
		__u8 x = raw[i];
		__u32 q = ((__u32)x * 205U) >> 11; // approximate x/10
		__u8 r = ( __u8 )( x - ( (__u8)(q * 10U) ) ); // r == x % 10 for 0..255
		out[i] = (unsigned char) r;
	}

	// 4) 确保第 0 字节不是 0（按你历史逻辑）
	if (out[0] == 0) out[0] = 1;
}


static __inline struct apm_span_context * build_sc_by_ipport(struct ebpf_proc_info proc_info, __u32 rip_net, __u32 raw_port) {
	__u32 key = 0;
	struct apm_span_context *cw_sc = bpf_map_lookup_elem(&apm_span_context_heap, &key);

	if (cw_sc == NULL) {
		return NULL;
	}

	struct apm_span_context *cw_psc = cw_get_parent_tracking_span();
	if (cw_psc) {
		copy_byte_arrays(cw_psc->trace_id, cw_sc->trace_id, APM_TRACE_ID_SIZE);
	}
	// new spanid
	generate_random_bytes(cw_sc->span_id, APM_SPAN_ID_SIZE);

	// set host_id/appid
	/*__u32 k0 = 0;
	struct trace_conf_t *trace_conf = trace_conf_map__lookup(&k0);
	if (trace_conf) {
//		for (int i = 0; i < 8; ++i) {
//			cw_bpf_debug("[Client] host_id:%02x", trace_conf->host_id[i]);
//		}
		copy_byte_arrays(trace_conf->host_id, cw_sc->host_id, APM_HOST_ID_SIZE);
//		copy_byte_arrays(trace_conf->app_id, cw_sc->app_id, APM_APP_ID_SIZE);
	}*/

	copy_byte_arrays(proc_info.instance_id, cw_sc->instance_id, APM_APP_ID_SIZE);
	copy_byte_arrays(proc_info.app_id, cw_sc->app_id, APM_APP_ID_SIZE);

	// set assumed_app_id
	unsigned char assumed_app_id[APM_ASSUMED_APP_ID_STRING_SIZE];
	ipport_to_16digits_from_u32_high(rip_net, raw_port, assumed_app_id);
	hex_string_to_bytes((char *) assumed_app_id, APM_ASSUMED_APP_ID_STRING_SIZE, cw_sc->assumed_app_id);

//	set_assumed_app_id_arrays(host, cw_sc->assumed_app_id, APM_ASSUMED_APP_ID_STRING_SIZE);
	return cw_sc;
}

/* 返回语言名称的函数：例如 "Go","Java","Nodejs","Nginx", ".net" ... */
static __always_inline const char *code_type_to_name(__u16 code_type) {
	switch (code_type) {
		case CodeTypeGo:                  return "Go";        // 1006
		case CodeTypeJava:
		case CodeTypeJavaAot:
		case CodeTypeJavaC:               return "Java";      // 1002,1102,1010 -> Java family
		case CodeTypeNode:                return "Nodejs";    // 1005
		case CodeTypePHP:                 return "PHP";       // 1001
		case CodeTypePython:              return "Python";    // 1003
		case CodeTypeDotNet:              return ".net";      // 1004
		case CodeTypeNetCore:
		case CodeTypeNetCoreAot:          return ".netCore";  // 1008,1108
		case CodeTypeC:                   return "C";         // 1007
		case CodeTypeWaitCheck:           return "WaitCheck"; // 0
//		case CodeTypeUnknown:             return "Unknown";   // -1
		default:
			return "Unknown";
	}
}

/* 返回两位数字码的函数：例如 "00" -> Go, "01" -> Java ... */
static __always_inline  char code_type_to_code(__u16 code_type) {
	switch (code_type) {
		case CodeTypeGo:                  return '0'; // Go
		case CodeTypeJava:
		case CodeTypeJavaAot:
		case CodeTypeJavaC:               return '1'; // Java family
		case CodeTypeNode:                return '2'; // Nodejs
		case CodeTypeNginx:               return '3'; // Nginx
		case CodeTypeDotNet:              return '4'; // .net
		case CodeTypeNetCore:
		case CodeTypeNetCoreAot:          return '5'; // .netCore
		case CodeTypePHP:                 return '6'; // PHP
		case CodeTypePython:              return '7'; // Python
		case CodeTypeC:                   return '8'; // C
		default:
			return '0'; // unknown / fallback
	}
}

// 假定已有：
// struct ebpf_proc_info { __u16 code_type; /* ... */ };
// BPF map 已声明为 proc_info_map

static __always_inline int mk_header_in_sk_msg(__u16 code_type) {
	/* 在 allowed_code_types 中查找 */
	__u8 *p = bpf_map_lookup_elem(&l4_header_code_types, &code_type);
	if (p && *p)
		return 1;
	return 0;
}