package service

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"net"
	"os"
	"path/filepath"
	"runtime"
	"time"

	"be.ems/src/modules/trace/model"
)

// TraceMsgToOamTraceData 结构体定义
type TraceMsgToOamTraceData struct {
	NfTraceMsg      *model.TraceMsg
	TimestampStr    string
	TracePayloadLen uint16
	TracePayload    []byte
}

// traceHandler 处理跟踪数据
func traceHandler(data []byte) (*TraceMsgToOamTraceData, error) {
	decodeData, err := decodeTraceData(data)
	if err != nil {
		return decodeData, err
	}
	// fmt.Printf("TraceHandler get oamData: %s,%+v\n, payload=len(%d,%d)", decodeData.TimestampStr, decodeData.NfTraceMsg, decodeData.TracePayloadLen, len(decodeData.TracePayload))
	// Return parsed message and payload
	if len(decodeData.TracePayload) != int(decodeData.TracePayloadLen) {
		return decodeData, fmt.Errorf("trace payload is bad, len=%d, shall be:%d", len(decodeData.TracePayload), int(decodeData.TracePayloadLen))
	}

	// 输出到文件
	filePath := fmt.Sprintf("/usr/local/omc/trace/task_%d.pcap", decodeData.NfTraceMsg.TraceId)
	if runtime.GOOS == "windows" {
		filePath = fmt.Sprintf("C:%s", filePath)
	}
	err = writePCAP(filePath, decodeData.NfTraceMsg.Timestamp, decodeData.TracePayload)

	return decodeData, err
}

// decodeTraceData 解析跟踪数据
func decodeTraceData(data []byte) (*TraceMsgToOamTraceData, error) {
	buf := bytes.NewBuffer(data)
	oamData := new(TraceMsgToOamTraceData)
	msg := new(model.TraceMsg)

	// 1. Parse Flag (1 byte)
	var flag uint8
	if err := binary.Read(buf, binary.BigEndian, &flag); err != nil {
		return nil, err
	}

	// Parse message type (bits 1-2)
	switch flag & 0x3 {
	case 0x1:
		msg.MsgType = model.MSG_TYPE_REQ
	case 0x2:
		msg.MsgType = model.MSG_TYPE_RSP
	}

	// Parse message direction (bits 3-4)
	switch flag & 0xc {
	case 0x4:
		msg.MsgDirect = model.MSG_DIRECT_SEND
	case 0x8:
		msg.MsgDirect = model.MSG_DIRECT_RECV
	}

	// 2. Parse TraceId (4 bytes)
	var traceId uint32
	if err := binary.Read(buf, binary.BigEndian, &traceId); err != nil {
		return nil, err
	}
	msg.TraceId = int(traceId)

	// 3. Parse IMSI (15 bytes fixed length)
	imsi := make([]byte, 15)
	if _, err := buf.Read(imsi); err != nil {
		return nil, err
	}
	msg.IMSI = string(imsi)

	// 4. Parse IfType (1 byte)
	ifTypeByte, err := buf.ReadByte()
	if err != nil {
		return nil, err
	}
	msg.IfType = byte2Iftype(ifTypeByte)

	// 5. Parse Timestamp (8 bytes)
	if err := binary.Read(buf, binary.BigEndian, &msg.Timestamp); err != nil {
		return nil, err
	}

	// 6. Parse SrcIp (4 bytes IPv4)
	srcIp := make([]byte, 4)
	if flag&0x20 != 0 {
		srcIp = make([]byte, 16)
	}
	if _, err := buf.Read(srcIp); err != nil {
		return nil, err
	}
	msg.SrcIpStr = net.IP(srcIp).String()

	// 7. Parse DstIp (4 bytes IPv4)
	dstIp := make([]byte, 4)
	if flag&0x20 != 0 {
		dstIp = make([]byte, 16)
	}
	if _, err := buf.Read(dstIp); err != nil {
		return nil, err
	}
	msg.DstIpStr = net.IP(dstIp).String()

	// 8. Parse NfName (variable length)
	nfNameLen, err := buf.ReadByte()
	if err != nil {
		return nil, err
	}
	nfName := make([]byte, nfNameLen)
	if _, err := buf.Read(nfName); err != nil {
		return nil, err
	}
	msg.NfName = string(nfName)

	// 9. Parse MsgEvent (variable length)
	msgEventLen, err := buf.ReadByte()
	if err != nil {
		return nil, err
	}
	msgEvent := make([]byte, msgEventLen)
	if _, err := buf.Read(msgEvent); err != nil {
		return nil, err
	}
	msg.MsgEvent = string(msgEvent)

	// 10. Parse ExtenBuf (variable length)
	extenBufLen, err := buf.ReadByte()
	if err != nil {
		return nil, err
	}
	if extenBufLen > 0 {
		extenBuf := make([]byte, extenBufLen)
		if _, err := buf.Read(extenBuf); err != nil {
			return nil, err
		}
		// TODO: Parse extended fields according to actual protocol
	}
	// 11. len of payload(2 byte)
	var len uint16
	if err := binary.Read(buf, binary.BigEndian, &len); err != nil {
		return nil, err
	}

	oamData.NfTraceMsg = msg
	oamData.TimestampStr = time.Unix(0, msg.Timestamp).Format("2006-01-02 15:04:05.999999999")
	oamData.TracePayloadLen = len
	oamData.TracePayload = buf.Bytes()
	return oamData, nil
}

// byte2Iftype 将字节转换为接口类型字符串
// 参考：3GPP TS 32.422 V17.0.0 (2022-06) 5G; 3GPP TS 29.244 V17.0.0 (2022-06) 5G
func byte2Iftype(val uint8) string {
	ret := ""
	switch val {
	case 1:
		ret = "N1"
	case 2:
		ret = "N2"
	case 3:
		ret = "N1/N2"
	case 4:
		ret = "N4"
	case 5:
		ret = "N5"
	case 7:
		ret = "N7"
	case 8:
		ret = "N8"
	case 10:
		ret = "N10"
	case 11:
		ret = "N11"
	case 12:
		ret = "N12"
	case 13:
		ret = "N13"
	case 14:
		ret = "N14"
	case 15:
		ret = "N15"
	case 20:
		ret = "N20"
	case 22:
		ret = "N22"
	case 40:
		ret = "N40"
	}
	return ret
}

// writePCAP 写入PCAP文件
func writePCAP(filename string, timeStamp int64, data []byte) error {
	var err error
	var file *os.File

	// 1. 创建目录（含权限控制）
	if err := os.MkdirAll(filepath.Dir(filename), 0775); err != nil {
		return err
	}

	// 2. 智能打开文件（原子操作避免竞态）
	if _, err = os.Stat(filename); os.IsNotExist(err) {
		file, err = os.Create(filename)
		if err != nil {
			return err
		}
		// 写入PCAP全局头（严格兼容Wireshark）
		fileHeader := [24]byte{
			0xD4, 0xC3, 0xB2, 0xA1, // magic_number (微秒级)
			0x02, 0x00, 0x04, 0x00, // version_major(2) + version_minor(4)
			0x00, 0x00, 0x00, 0x00, // thiszone (UTC)
			0x00, 0x00, 0x00, 0x00, // sigfigs (固定0)
			0x00, 0x00, 0x04, 0x00, // snaplen (1024)
			0x71, 0x00, 0x00, 0x00, // network (LINKTYPE_LINUX_SLL)
		}
		if _, err := file.Write(fileHeader[:]); err != nil {
			return err
		}
	} else {
		// 追加模式打开（避免截断已有内容）
		file, err = os.OpenFile(filename, os.O_WRONLY|os.O_APPEND|os.O_SYNC, 0666)
		if err != nil {
			return err
		}
	}
	defer file.Close()

	// 3. 构造Linux cooked头（RFC 3580规范）
	linuxSLLHeaderLen := 16 // Linux cooked模式头长度
	cookedHeader := make([]byte, linuxSLLHeaderLen)
	binary.BigEndian.PutUint16(cookedHeader[0:2], 0x0000)   // 数据包类型（主机→网络）
	binary.BigEndian.PutUint16(cookedHeader[2:4], 0x0304)   // 地址类型（ARPHRD_ETHER）
	binary.BigEndian.PutUint16(cookedHeader[4:6], 0x0008)   // 协议类型（ETH_P_IP）
	binary.BigEndian.PutUint16(cookedHeader[14:16], 0x0800) // 数据包类型（PACKET_HOST）

	// 4. 合并链路层头与数据（兼容IPv4选项）
	fullData := append(cookedHeader, data...)
	pktLen := len(fullData)

	// 5. 生成精确时间戳（处理闰秒和时区）
	t := time.Unix(0, timeStamp).UTC()
	if t.IsZero() {
		t = time.Now().UTC()
	}
	secs := t.Unix()
	usecs := t.Nanosecond() / 1000 // 微秒级时间戳

	// 6. 构造PCAP报文头（16字节）
	var packetHeader [16]byte
	binary.LittleEndian.PutUint32(packetHeader[0:4], uint32(secs))     // 时间戳秒
	binary.LittleEndian.PutUint32(packetHeader[4:8], uint32(usecs))    // 时间戳微秒
	binary.LittleEndian.PutUint32(packetHeader[8:12], uint32(pktLen))  // 捕获长度
	binary.LittleEndian.PutUint32(packetHeader[12:16], uint32(pktLen)) // 原始长度

	// 7. 原子写入操作（避免部分写入）
	buf := new(bytes.Buffer)
	buf.Write(packetHeader[:])
	buf.Write(fullData)
	if _, err := file.Write(buf.Bytes()); err != nil {
		return err
	}

	// 8. 强制刷盘并验证写入
	return file.Sync()
}
