package service

import (
	"encoding/base64"
	"fmt"
	"net"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"sync"
	"sync/atomic"
	"time"

	"github.com/gopacket/gopacket"
	"github.com/gopacket/gopacket/layers"
	"github.com/gopacket/gopacket/pcap"
	"github.com/gopacket/gopacket/pcapgo"

	"be.ems/src/framework/logger"
	wsService "be.ems/src/modules/ws/service"
)

// Task  任务信息
type Task struct {
	TaskNo string         // 任务编号
	Handle *pcap.Handle   // 捕获句柄
	File   *os.File       // 捕获信息输出文件句柄
	Writer *pcapgo.Writer // 捕获信息输出句柄
	Filter string         // 过滤表达式
	Ticker *time.Ticker   // 任务失效定时器
}

// FrameMeta 数据帧元信息
type FrameMeta struct {
	Number      int    `json:"number"`
	Time        int64  `json:"time"`
	Source      string `json:"source"`
	Destination string `json:"destination"`
	Protocol    string `json:"protocol"`
	Length      int    `json:"length"`
	Info        string `json:"info"`
	Data        string `json:"data"` // 原始数据byte[] base64 编码数据
}

// 实例化服务层 Packet 结构体
var NewPacket = &Packet{
	taskMap: sync.Map{},
}

// 信令跟踪 服务层处理
type Packet struct {
	taskMap sync.Map
}

// NetworkDevices 获取网卡设备信息
func (s *Packet) NetworkDevices() []map[string]any {
	arr := make([]map[string]any, 0)
	devices, err := pcap.FindAllDevs()
	if err != nil {
		logger.Errorf("interfaces find all devices err: %s", err.Error())
		return arr
	}

	for _, device := range devices {
		if len(device.Addresses) == 0 {
			continue
		}

		lable := device.Description
		if lable == "" {
			lable = device.Name
		}
		item := map[string]any{
			"id":       device.Name,
			"label":    lable,
			"children": []map[string]any{},
		}

		for _, address := range device.Addresses {
			if address.IP != nil {
				ip := address.IP.String()
				item["children"] = append(item["children"].([]map[string]any), map[string]any{"id": ip, "label": ip})
			}
		}
		arr = append(arr, item)
	}

	return arr
}

// LiveStart 开始捕获数据
func (s *Packet) LiveStart(taskNo, deviceName, filterBPF string, outputPCAP bool) (string, error) {
	if _, ok := s.taskMap.Load(taskNo); ok {
		return "", fmt.Errorf("task no. %s already exist", taskNo)
	}

	// Verify the specified network interface exists
	device, deviceOk := s.verifyDevice(deviceName)
	if !deviceOk {
		return "", fmt.Errorf("network device not exist: %s", deviceName)
	}

	// listening on eth1, link-type EN10MB (Ethernet), snapshot length 262144 bytes
	snapshotLength := 262144

	// open device
	handle, err := pcap.OpenLive(device, int32(snapshotLength), true, pcap.BlockForever)
	if err != nil {
		logger.Errorf("open live err: %s", err.Error())
		if strings.Contains(err.Error(), "operation not permitted") {
			return "", fmt.Errorf("you don't have permission to capture on that/these device(s)")
		}
		return "", err
	}

	// write a new file
	var w *pcapgo.Writer
	var f *os.File
	if outputPCAP {
		// 网管本地路径
		localFilePath := fmt.Sprintf("/usr/local/omc/packet/%s.pcap", taskNo)
		if runtime.GOOS == "windows" {
			localFilePath = fmt.Sprintf("C:%s", localFilePath)
		}
		f, w, err = s.outputPCAPFile(uint32(snapshotLength), handle.LinkType(), localFilePath)
		if err != nil {
			return "", err
		}
	}

	// set filter
	if filterBPF != "" {
		if err = handle.SetBPFFilter(filterBPF); err != nil {
			logger.Errorf("packet BPF Filter %s => %s", filterBPF, err.Error())
			filterBPF = ""
		}
	}

	// save tasks
	taskInfo := &Task{
		TaskNo: taskNo,
		Handle: handle,
		File:   f,
		Writer: w,
		Filter: filterBPF,
		Ticker: time.NewTicker(time.Second * 120),
	}

	go s.capturePacketSource(taskInfo)
	s.taskMap.Store(taskNo, taskInfo)
	return fmt.Sprintf("task no: %s initiated", taskNo), nil
}

// verifyDevice 检查网卡设备是否存在
func (s *Packet) verifyDevice(str string) (string, bool) {
	devices, err := pcap.FindAllDevs()
	if err != nil {
		logger.Errorf("interfaces find all devices err: %s", err.Error())
		return "", false
	}
	for _, device := range devices {
		if len(device.Addresses) == 0 {
			continue
		}
		if device.Name == str {
			return device.Name, true
		}
		for _, address := range device.Addresses {
			if address.IP.String() == str {
				return device.Name, true
			}
		}
	}
	return "", false
}

// capturePacketSource 捕获数据
func (s *Packet) capturePacketSource(taskInfo *Task) {
	// capture packets
	packetSource := gopacket.NewPacketSource(taskInfo.Handle, taskInfo.Handle.LinkType())
	packetSource.Lazy = false
	packetSource.NoCopy = true
	packetSource.DecodeStreamsAsDatagrams = true

	// 协程停止后关闭句柄并移除任务信息
	defer func() {
		taskInfo.Ticker.Stop()
		taskInfo.Handle.Close()
		if taskInfo.File != nil {
			taskInfo.File.Close()
		}
		s.taskMap.Delete(taskInfo.TaskNo)
	}()

	var frameNumber int64 = 0 // 帧编号

	for {
		select {
		case <-taskInfo.Ticker.C:
			return
		case packet := <-packetSource.Packets():
			if packet == nil {
				continue
			}
			// 如果延迟超过1秒跳过
			timeDiff := time.Since(packet.Metadata().Timestamp)
			if timeDiff > time.Second {
				continue
			}

			// 使用原子操作获取当前帧号并自增
			currentFrameNumber := atomic.AddInt64(&frameNumber, 1)
			frameSrc := ""      // 源主机IP
			frameDst := ""      // 目的主机IP
			frameProtocol := "" // 协议
			frameInfo := ""     // 信息
			// fmt.Printf("----------  packet %d  layers:%d time: %s, len: %d \n", currentFrameNumber, len(packet.Layers()), packet.Metadata().Timestamp, packet.Metadata().Length)

			// 网络层
			// fmt.Println(packet.NetworkLayer())
			if networkLayer := packet.NetworkLayer(); networkLayer != nil {
				src, dst := networkLayer.NetworkFlow().Endpoints()
				frameSrc = src.String()
				frameDst = dst.String()
				if frameDst == "ff:ff:ff:ff" {
					frameDst = "Broadcast"
				}
			}

			// 传输层
			// fmt.Println(packet.TransportLayer())
			if transportLayer := packet.TransportLayer(); transportLayer != nil {
				frameProtocol = transportLayer.LayerType().String()
				switch layer := transportLayer.(type) {
				case *layers.TCP: // 传输控制协议，提供可靠的数据传输。
					var flagsDesc []string
					if layer.FIN {
						flagsDesc = append(flagsDesc, "FIN")
					}
					if layer.SYN {
						flagsDesc = append(flagsDesc, "SYN")
					}
					if layer.RST {
						flagsDesc = append(flagsDesc, "RST")
					}
					if layer.PSH {
						flagsDesc = append(flagsDesc, "PSH")
					}
					if layer.ACK {
						flagsDesc = append(flagsDesc, "ACK")
					}
					if layer.URG {
						flagsDesc = append(flagsDesc, "URG")
					}
					if layer.ECE {
						flagsDesc = append(flagsDesc, "ECE")
					}
					if layer.CWR {
						flagsDesc = append(flagsDesc, "CWR")
					}
					if layer.NS {
						flagsDesc = append(flagsDesc, "NS")
					}

					frameInfo = fmt.Sprintf("%v -> %v [%s], Seq=%d Ack=%d Win=%d Len=%d ", layer.SrcPort, layer.DstPort, strings.Join(flagsDesc, ", "), layer.Seq, layer.Ack, layer.Window, len(layer.Payload))
				case *layers.UDP: // 用户数据报协议，提供无连接的快速数据传输。
					frameInfo = fmt.Sprintf("%v -> %v Len=%d ", layer.SrcPort, layer.DstPort, len(layer.Payload))
				case *layers.UDPLite:
					frameInfo = fmt.Sprintf("%v -> %v Len=%d ", layer.SrcPort, layer.DstPort, len(layer.Payload))
				case *layers.SCTP: // 流控制传输协议，支持多流和多宿主机。
					frameInfo = fmt.Sprintf("%v -> %v Len=%d ", layer.SrcPort, layer.DstPort, len(layer.Payload))
				}
			}

			// 应用协议层判断
			switch {
			case packet.Layer(layers.LayerTypeARP) != nil:
				arp := packet.Layer(layers.LayerTypeARP).(*layers.ARP)
				frameSrc = net.IP(arp.SourceProtAddress).String()
				frameDst = net.IP(arp.DstProtAddress).String()
				frameProtocol = "ARP"
				frameInfo = fmt.Sprintf("Who has %s? Tell %s", frameDst, frameSrc)
			case packet.Layer(layers.LayerTypeVRRP) != nil:
				frameProtocol = "VRRP"
				frameInfo = "Announcement (v2)"
			case packet.Layer(layers.LayerTypeIGMP) != nil:
				switch layer := packet.Layer(layers.LayerTypeIGMP).(type) {
				case *layers.IGMP:
					frameProtocol = fmt.Sprintf("IGMPv%d", layer.Version)
					frameInfo = fmt.Sprintf("%s %s", layer.Type.String(), layer.GroupAddress.String())
				case *layers.IGMPv1or2:
					frameProtocol = fmt.Sprintf("IGMPv%d", layer.Version)
					frameInfo = fmt.Sprintf("%s %s", layer.Type.String(), layer.GroupAddress.String())
				}
			case packet.Layer(layers.LayerTypeICMPv4) != nil:
				icmpv4 := packet.Layer(layers.LayerTypeICMPv4).(*layers.ICMPv4)
				frameProtocol = "ICMP"
				frameInfo = icmpv4.TypeCode.String()
			case packet.Layer(layers.LayerTypeICMPv6) != nil:
				icmpv6 := packet.Layer(layers.LayerTypeICMPv6).(*layers.ICMPv6)
				frameProtocol = "ICMPv6"
				frameInfo = icmpv6.TypeCode.String()
			case packet.Layer(layers.LayerTypeSTP) != nil:
				stp := packet.Layer(layers.LayerTypeSTP).(*layers.STP)
				rootIdentifier := stp.RouteID
				frameSrc = rootIdentifier.HwAddr.String()
				frameDst = stp.BridgeID.HwAddr.String()
				frameProtocol = "STP"
				frameInfo = fmt.Sprintf("MST. Root = %d/%d/%s  Cost = %d  Port = 0x%x", rootIdentifier.Priority, rootIdentifier.SysID, frameSrc, stp.Cost, stp.PortID)
			case packet.Layer(layers.LayerTypeSIP) != nil:
				sip := packet.Layer(layers.LayerTypeSIP).(*layers.SIP)
				frameProtocol = "SIP"
				if sip.IsResponse {
					frameInfo = fmt.Sprintf("%d %s", sip.ResponseCode, sip.ResponseStatus)
				} else {
					frameInfo = fmt.Sprintf("%s %s", sip.Method, sip.RequestURI)
				}
			case packet.Layer(layers.LayerTypeDNS) != nil:
				dns := packet.Layer(layers.LayerTypeDNS).(*layers.DNS)
				frameProtocol = "DNS"
				question := []string{}
				if len(dns.Questions) > 0 {
					question = append(question, fmt.Sprintf("%s %s", dns.Questions[0].Type, dns.Questions[0].Name))
				}
				frameInfo = fmt.Sprintf("%s %s 0x%x %s Answers %d", dns.ResponseCode.String(), dns.OpCode.String(), dns.ID, question, len(dns.Answers))
			case packet.Layer(layers.LayerTypeDHCPv6) != nil:
				dhcpv6 := packet.Layer(layers.LayerTypeDHCPv6).(*layers.DHCPv6)
				frameProtocol = "DHCPv6"
				frameInfo = fmt.Sprintf("%s XID: 0x%+x", dhcpv6.MsgType.String(), dhcpv6.TransactionID)
			case packet.Layer(layers.LayerTypeTLS) != nil:
				tls := packet.Layer(layers.LayerTypeTLS).(*layers.TLS)
				if len(tls.AppData) > 0 {
					item := tls.AppData[0]
					frameProtocol = item.Version.String()
					frameInfo = item.ContentType.String()
				} else if len(tls.Handshake) > 0 {
					item := tls.Handshake[0]
					frameProtocol = item.ClientHello.ProtocolVersion.String()
					frameInfo = "Client Hello"
				} else {
					frameProtocol = "TLS"
					frameInfo = "Unknown"
				}
			}

			if frameProtocol == "" {
				continue
			}

			// 数据
			frameMeta := FrameMeta{
				Number:      int(currentFrameNumber),
				Time:        packet.Metadata().Timestamp.UnixNano(),
				Source:      frameSrc,
				Destination: frameDst,
				Protocol:    frameProtocol,
				Length:      packet.Metadata().Length,
				Info:        frameInfo,
				Data:        base64.StdEncoding.EncodeToString(packet.Data()),
			}
			// 推送到ws订阅组
			wsService.NewWSSend.ByGroupID(fmt.Sprintf("%s_%s", wsService.GROUP_TRACE_PACKET, taskInfo.TaskNo), frameMeta)

			// 写入文件
			if taskInfo.Writer != nil {
				taskInfo.Writer.WritePacket(packet.Metadata().CaptureInfo, packet.Data())
			}
		}
	}
}

// outputPCAPFile 输出 pcap 文件
// 新文件时需要 snaplen 最大长度 linktype 链路类型
func (s *Packet) outputPCAPFile(snaplen uint32, linktype layers.LinkType, outputFile string) (*os.File, *pcapgo.Writer, error) {
	var err error
	var f *os.File
	if err := os.MkdirAll(filepath.Dir(outputFile), 0775); err != nil {
		return nil, nil, err
	}

	// 检查文件是否存在
	if _, err = os.Stat(outputFile); os.IsNotExist(err) {
		f, err = os.Create(outputFile)
		if err != nil {
			return nil, nil, err
		}
		w := pcapgo.NewWriter(f)
		w.WriteFileHeader(snaplen, linktype) // new file, must do this.
		return f, w, nil
	}

	f, err = os.OpenFile(outputFile, os.O_APPEND, 0700)
	if err != nil {
		return nil, nil, err
	}
	w := pcapgo.NewWriter(f)
	return f, w, nil
}

// LiveFilter 捕获过滤
func (s *Packet) LiveFilter(taskNo, expr string) error {
	info, ok := s.taskMap.Load(taskNo)
	if !ok {
		return fmt.Errorf("task no: %s does not exist or has stopped", taskNo)
	}
	task := info.(*Task)
	task.Filter = expr
	err := task.Handle.SetBPFFilter(expr)
	if err != nil {
		logger.Errorf("packet BPF Filter %s => %s", expr, err.Error())
		return fmt.Errorf("can't parse filter expression")
	}
	return nil
}

// LiveTimeout 更新捕获失效时间
func (s *Packet) LiveTimeout(taskNo string, seconds int) error {
	info, ok := s.taskMap.Load(taskNo)
	if !ok {
		return fmt.Errorf("task no: %s does not exist or has stopped", taskNo)
	}
	info.(*Task).Ticker.Reset(time.Duration(seconds) * time.Second)
	return nil
}

// LiveStop 停止捕获数据
func (s *Packet) LiveStop(taskNo string) error {
	info, ok := s.taskMap.Load(taskNo)
	if !ok {
		return fmt.Errorf("task no: %s does not exist or has stopped", taskNo)
	}
	info.(*Task).Ticker.Reset(time.Millisecond)
	return nil
}
