package netstack

import (
	"bytes"
	"log"

	"gvisor.dev/gvisor/pkg/tcpip"
	"gvisor.dev/gvisor/pkg/tcpip/network/ipv4"
	"gvisor.dev/gvisor/pkg/tcpip/stack"
	"gvisor.dev/gvisor/pkg/tcpip/transport/tcp"
	"gvisor.dev/gvisor/pkg/waiter"
)

func handleConnection(ep tcpip.Endpoint, wq *waiter.Queue) {
	// 确保连接最终关闭
	defer ep.Close()

	// 创建等待队列用于读取事件通知
	// var wq waiter.Queue

	// 创建可读事件监听器（waiter.Entry）
	// EventIn: 当端点有数据可读时触发
	waitEntry, notifyCh := waiter.NewChannelEntry(waiter.EventIn)
	wq.EventRegister(&waitEntry)
	// 退出时自动取消事件注册
	defer wq.EventUnregister(&waitEntry)

	// 连接处理主循环
	for {
		var buf bytes.Buffer
		// 尝试读取数据（非阻塞模式）
		_, err := ep.Read(&buf, tcpip.ReadOptions{})
		if err != nil {
			switch err.(type) {
			case *tcpip.ErrWouldBlock: // 处理暂时无数据的情况
				<-notifyCh // 等待可读事件通知
				continue
			case *tcpip.ErrNotConnected: // 处理连接关闭的情况
				log.Println("Connection closed") // 打印连接关闭信息
				return                           // 结束连接处理
			}
			log.Println(err) // 打印错误信息
			return           // 其他错误直接返回
		}

		// 回显数据：将接收到的数据原样写回
		var r bytes.Reader
		r.Reset(buf.Bytes()) // 将缓冲区数据载入读取器
		// 写入数据到TCP连接
		_, err = ep.Write(&r, tcpip.WriteOptions{})
		if err != nil {
			return // 写入失败时结束连接
		}
	}
}

func startTCPServer(s *stack.Stack) {
	// 创建事件等待队列（用于异步I/O通知）
	var wq waiter.Queue

	// 创建TCP端点（相当于socket）
	// 参数说明：
	// - tcp.ProtocolNumber: TCP协议号(6)
	// - ipv4.ProtocolNumber: IPv4协议号(0x0800)
	// - &wq: 关联的等待队列
	ep, err := s.NewEndpoint(tcp.ProtocolNumber, ipv4.ProtocolNumber, &wq)
	if err != nil {
		panic(err)
	}

	// 绑定到指定网络接口（NIC 1）和端口
	// NIC: 网络接口控制器编号（虚拟网卡）
	if err := ep.Bind(tcpip.FullAddress{
		NIC: 1,
		// Addr: tcpip.AddrFromSlice(net.ParseIP("192.168.3.3").To4()),
		Addr: tcpip.Address{}, // 零值表示所有IP地址
		Port: 80,
	}); err != nil {
		panic(err)
	}

	// 启动监听，设置最大等待连接队列长度
	if err := ep.Listen(10); err != nil {
		panic(err)
	}

	// 持续接受新连接的循环
	for {
		var addr tcpip.FullAddress
		// 非阻塞式接受连接
		newEP, waitq, err := ep.Accept(&addr)
		if err != nil {
			switch err.(type) {
			case *tcpip.ErrWouldBlock: // 处理暂时无连接的情况
				// 注册读事件监听
				waitEntry, notifyCh := waiter.NewChannelEntry(waiter.EventIn)
				wq.EventRegister(&waitEntry)
				// 阻塞等待直到新连接到达
				<-notifyCh
				wq.EventUnregister(&waitEntry)
				continue
			case *tcpip.ErrInvalidEndpointState: // 处理端点状态错误
				continue
			default:
				log.Println(err)
				continue
			}
		}

		log.Printf("Accepted connection from %s:%d\n", addr.Addr, addr.Port)

		// 获取新连接的端点
		go handleConnection(newEP, waitq) // 传递正确的连接端点
	}
}
