package connect

import (
	"context"
	"encoding/binary"
	"fmt"
	"io"
	"net"
	"sync"
	"time"

	"go.uber.org/zap"
)

// FakeTCPConn FakeTCP 连接（UDP 包封装为 TCP 流）
type FakeTCPConn struct {
	conn       net.Conn
	mu         sync.Mutex
	closed     bool
	readBuffer []byte
}

// NewFakeTCPConn 创建 FakeTCP 连接
func NewFakeTCPConn(conn net.Conn) *FakeTCPConn {
	return &FakeTCPConn{
		conn:       conn,
		readBuffer: make([]byte, 0),
	}
}

// Read 读取数据（带长度前缀解析）
func (c *FakeTCPConn) Read(b []byte) (int, error) {
	c.mu.Lock()
	defer c.mu.Unlock()

	// 如果缓冲区有数据，直接返回
	if len(c.readBuffer) > 0 {
		n := copy(b, c.readBuffer)
		c.readBuffer = c.readBuffer[n:]
		return n, nil
	}

	// 读取长度前缀（4 字节）
	var length uint32
	if err := binary.Read(c.conn, binary.BigEndian, &length); err != nil {
		return 0, err
	}

	// 限制最大长度（防止恶意攻击）
	if length > 65535 {
		return 0, fmt.Errorf("packet too large: %d bytes", length)
	}

	// 读取实际数据
	data := make([]byte, length)
	if _, err := io.ReadFull(c.conn, data); err != nil {
		return 0, err
	}

	// 返回请求的数据
	n := copy(b, data)
	if n < len(data) {
		// 剩余数据存入缓冲区
		c.readBuffer = data[n:]
	}

	return n, nil
}

// Write 写入数据（添加 4 字节长度前缀）
func (c *FakeTCPConn) Write(b []byte) (int, error) {
	c.mu.Lock()
	defer c.mu.Unlock()

	if c.closed {
		return 0, fmt.Errorf("connection closed")
	}

	// 写入长度前缀
	length := uint32(len(b))
	if err := binary.Write(c.conn, binary.BigEndian, length); err != nil {
		return 0, err
	}

	// 写入实际数据
	n, err := c.conn.Write(b)
	return n, err
}

// Close 关闭连接
func (c *FakeTCPConn) Close() error {
	c.mu.Lock()
	defer c.mu.Unlock()

	c.closed = true
	return c.conn.Close()
}

// LocalAddr 本地地址
func (c *FakeTCPConn) LocalAddr() net.Addr {
	return c.conn.LocalAddr()
}

// RemoteAddr 远程地址
func (c *FakeTCPConn) RemoteAddr() net.Addr {
	return c.conn.RemoteAddr()
}

// SetDeadline 设置截止时间
func (c *FakeTCPConn) SetDeadline(t time.Time) error {
	return c.conn.SetDeadline(t)
}

// SetReadDeadline 设置读截止时间
func (c *FakeTCPConn) SetReadDeadline(t time.Time) error {
	return c.conn.SetReadDeadline(t)
}

// SetWriteDeadline 设置写截止时间
func (c *FakeTCPConn) SetWriteDeadline(t time.Time) error {
	return c.conn.SetWriteDeadline(t)
}

// DialFakeTCP 拨号 FakeTCP 连接
func DialFakeTCP(ctx context.Context, network, addr string, logger *zap.Logger) (net.Conn, error) {
	logger.Debug("dialing FakeTCP", zap.String("addr", addr))

	// 建立 TCP 连接
	conn, err := (&net.Dialer{}).DialContext(ctx, network, addr)
	if err != nil {
		return nil, fmt.Errorf("failed to dial TCP: %w", err)
	}

	// 包装为 FakeTCP 连接
	return NewFakeTCPConn(conn), nil
}

// ListenFakeTCP 监听 FakeTCP 端口
func ListenFakeTCP(network, addr string, logger *zap.Logger) (net.Listener, error) {
	logger.Info("listening FakeTCP", zap.String("addr", addr))

	// 监听 TCP 端口
	listener, err := net.Listen(network, addr)
	if err != nil {
		return nil, fmt.Errorf("failed to listen TCP: %w", err)
	}

	return &fakeTCPListener{
		Listener: listener,
		logger:   logger,
	}, nil
}

// fakeTCPListener FakeTCP 监听器
type fakeTCPListener struct {
	net.Listener
	logger *zap.Logger
}

// Accept 接受连接并包装为 FakeTCPConn
func (l *fakeTCPListener) Accept() (net.Conn, error) {
	conn, err := l.Listener.Accept()
	if err != nil {
		return nil, err
	}

	l.logger.Debug("accepted FakeTCP connection", zap.String("addr", conn.RemoteAddr().String()))
	return NewFakeTCPConn(conn), nil
}

// FakeTCPFactory FakeTCP 传输工厂
type FakeTCPFactory struct {
	logger *zap.Logger
}

// NewFakeTCPFactory 创建 FakeTCP 工厂
func NewFakeTCPFactory(logger *zap.Logger) *FakeTCPFactory {
	return &FakeTCPFactory{
		logger: logger,
	}
}

// Layer 返回传输层类型
func (f *FakeTCPFactory) Layer() Layer {
	return LayerFakeTCP
}

// Name 返回名称
func (f *FakeTCPFactory) Name() string {
	return "FakeTCP"
}

// Dial 建立 FakeTCP 连接
func (f *FakeTCPFactory) Dial(ctx context.Context, config *DialConfig) (net.Conn, error) {
	f.logger.Info("开始建立 FakeTCP 连接",
		zap.String("peer_id", config.PeerID))

	// 1. 解析对端地址（PeerID 格式应为 "ip:port"）
	if config.PeerID == "" {
		return nil, fmt.Errorf("PeerID 为空")
	}

	// 2. 建立 TCP 连接
	dialer := &net.Dialer{Timeout: config.Timeout}
	conn, err := dialer.DialContext(ctx, "tcp", config.PeerID)
	if err != nil {
		return nil, fmt.Errorf("TCP 连接失败：%w", err)
	}

	// 3. 包装为 FakeTCP 连接（UDP 包封装为 TCP 流）
	fakeConn := NewFakeTCPConn(conn)

	f.logger.Info("FakeTCP 连接建立成功",
		zap.String("peer_id", config.PeerID),
		zap.String("local_addr", conn.LocalAddr().String()),
		zap.String("remote_addr", conn.RemoteAddr().String()))

	return fakeConn, nil
}
