package connect

import (
	"context"
	"fmt"
	"net"
	"sync"
	"time"

	"go.uber.org/zap"
)

// RealTCPConn 真正的 TCP 连接（用于传输 WireGuard 密文）
// 与 FakeTCP 不同，RealTCP 不封装 UDP 包，直接传输原始数据
type RealTCPConn struct {
	conn   net.Conn
	closed bool
	mu     sync.Mutex
}

// NewRealTCPConn 创建 RealTCP 连接
func NewRealTCPConn(conn net.Conn) *RealTCPConn {
	return &RealTCPConn{
		conn: conn,
	}
}

// Read 读取数据
func (c *RealTCPConn) Read(b []byte) (int, error) {
	c.mu.Lock()
	defer c.mu.Unlock()

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

	return c.conn.Read(b)
}

// Write 写入数据
func (c *RealTCPConn) Write(b []byte) (int, error) {
	c.mu.Lock()
	defer c.mu.Unlock()

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

	return c.conn.Write(b)
}

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

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

// RealTCPFactory RealTCP 传输工厂
type RealTCPFactory struct {
	logger *zap.Logger
}

// NewRealTCPFactory 创建 RealTCP 工厂
func NewRealTCPFactory(logger *zap.Logger) *RealTCPFactory {
	return &RealTCPFactory{
		logger: logger,
	}
}

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

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

// Dial 建立 RealTCP 连接
func (f *RealTCPFactory) Dial(ctx context.Context, config *DialConfig) (net.Conn, error) {
	f.logger.Info("开始建立 RealTCP 连接",
		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. 包装为 RealTCP 连接（直接传输原始数据）
	realConn := NewRealTCPConn(conn)

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

	return realConn, nil
}

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

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

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

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

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

// DialRealTCP 拨号 RealTCP 连接
func DialRealTCP(ctx context.Context, network, addr string, logger *zap.Logger) (net.Conn, error) {
	logger.Debug("dialing RealTCP", 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)
	}

	// 包装为 RealTCP 连接
	return NewRealTCPConn(conn), nil
}

// ListenRealTCP 监听 RealTCP 端口
func ListenRealTCP(network, addr string, logger *zap.Logger) (net.Listener, error) {
	logger.Info("listening RealTCP", 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 &realTCPListener{
		Listener: listener,
		logger:   logger,
	}, nil
}

// realTCPListener RealTCP 监听器
type realTCPListener struct {
	net.Listener
	logger *zap.Logger
}

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

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