package connect

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

	"go.uber.org/zap"
)

// Layer 传输层类型（9 层策略）
type Layer int

const (
	// LayerDirectUDP Direct-UDP 直连（WireGuard over UDP）- 最高效
	LayerDirectUDP Layer = iota

	// LayerFakeTCP Direct-FakeTCP（UDP 封装 TCP 头部，欺骗防火墙）
	LayerFakeTCP

	// LayerRealTCP Direct-RealTCP（P2P TCP 直连）
	LayerRealTCP

	// LayerTURNUDP TURN-UDP 中继（标准 RFC 5766）
	LayerTURNUDP

	// LayerTURNQUIC TURN-QUIC 中继（私有扩展，RFC 9000）
	LayerTURNQUIC

	// LayerTURNTCP TURN-TCP 中继（TCP 中继）
	LayerTURNTCP

	// LayerTURNTLS TURN-TLS 中继（TLS 加密，RFC 8656）
	LayerTURNTLS

	// LayerWebRTC WebRTC DataChannel（DTLS 加密）
	LayerWebRTC

	// LayerWS WS/WSS 兜底（仅 80/443 端口，终极兜底）
	LayerWS

	// LayerCount 传输层总数
	LayerCount
)

// String 实现 Stringer 接口
func (l Layer) String() string {
	switch l {
	case LayerDirectUDP:
		return "Direct-UDP"
	case LayerFakeTCP:
		return "Direct-FakeTCP"
	case LayerRealTCP:
		return "Direct-RealTCP"
	case LayerTURNUDP:
		return "TURN-UDP"
	case LayerTURNQUIC:
		return "TURN-QUIC"
	case LayerTURNTCP:
		return "TURN-TCP"
	case LayerTURNTLS:
		return "TURN-TLS"
	case LayerWebRTC:
		return "WebRTC"
	case LayerWS:
		return "WS/WSS"
	default:
		return "Unknown"
	}
}

// DefaultLayerOrder 默认优先级顺序（从最优到兜底）
// 根据 MeshRay_项目文档 v2.0.1 第 132-153 行定义
var DefaultLayerOrder = []Layer{
	LayerDirectUDP, // 1. Direct-UDP - 公网/锥型 NAT，首选链路
	LayerFakeTCP,   // 2. Direct-FakeTCP - 校园网、酒店 Wi-Fi、UDP 被 QoS 限速
	LayerRealTCP,   // 3. Direct-RealTCP - 完全禁用 UDP，仅允许 TCP 出站
	LayerTURNUDP,   // 4. TURN-UDP 中继 - 无 P2P 直连，但 UDP 可通
	LayerTURNQUIC,  // 5. TURN-QUIC 中继 - UDP 可通但弱网（4G/5G、高丢包）【私有扩展】
	LayerTURNTCP,   // 6. TURN-TCP 中继 - UDP 封禁，仅放行 TCP
	LayerTURNTLS,   // 7. TURN-TLS 中继 - 企业防火墙 DPI，仅放行 HTTPS
	LayerWebRTC,    // 8. WebRTC 终极兜底 - 最严格隔离内网、代理环境
	LayerWS,        // 9. WS/WSS 兜底 - 仅放行 80/443 端口，且封锁 TURN
}

// TransportFactory 传输工厂接口 - 每种传输方式必须实现
type TransportFactory interface {
	// Layer 返回传输层类型
	Layer() Layer

	// Dial 建立连接到对端
	// 返回标准的 net.Conn 接口
	Dial(ctx context.Context, config *DialConfig) (net.Conn, error)

	// Name 返回传输方式名称（用于日志）
	Name() string
}

// DialConfig 拨号配置
type DialConfig struct {
	// PeerID 对端标识
	PeerID string

	// PeerPublicKey 对端公钥
	PeerPublicKey string

	// STUNServers STUN 服务器列表（用于 P2P）
	STUNServers []string

	// TURNServers TURN 服务器列表
	TURNServers []string

	// WSServers WebSocket 服务器列表
	WSServers []string

	// SignalingServers WebRTC 第三方信令服务器列表
	SignalingServers []string

	// ICESServers ICE 服务器列表（STUN+TURN 的组合）
	ICESServers []string

	// Timeout 连接超时
	Timeout time.Duration

	// Logger 日志记录器
	Logger *zap.Logger
}

// StrategyScheduler 9 层策略调度器（主动调度层）
// 职责：
// 1. 按优先级选择链路（P2P → Mesh中继 → TURN-UDP → ... → WS/WSS）
// 2. 根据网络环境自动切换（500ms 超时 / 10s 丢包率 > 10%）
// 3. 切换后探测恢复并自动切回高性能链路（30s）
type StrategyScheduler struct {
	layerFactories map[Layer]TransportFactory // 各层的工厂
	layerOrder     []Layer                    // 优先级顺序
	logger         *zap.Logger

	// 每个 Peer 的降级控制器
	fallbackControllers map[string]*FallbackController // peerID -> controller
	fallbackMu          sync.RWMutex

	// 当前活跃连接
	activeConnections map[string]activeConn // peerID -> 连接信息
	connMu            sync.RWMutex

	// 统计
	stats *SchedulerStats

	// 连接变更回调（通知上层 ConnManager）
	OnConnectionUpdate func(peerID string, conn net.Conn, err error)
}

// activeConn 活跃连接信息
type activeConn struct {
	conn        net.Conn
	layer       Layer
	peerID      string
	established time.Time
	config      *DialConfig
}

// SchedulerStats 调度器统计
type SchedulerStats struct {
	mu             sync.RWMutex
	totalDials     int64
	successDials   int64
	fallbackCount  int64
	recoveryCount  int64
	layerDialCount map[Layer]int64
	layerFailCount map[Layer]int64
}

// NewStrategyScheduler 创建策略调度器
func NewStrategyScheduler(logger *zap.Logger) *StrategyScheduler {
	return &StrategyScheduler{
		layerFactories:      make(map[Layer]TransportFactory),
		layerOrder:          DefaultLayerOrder,
		logger:              logger,
		fallbackControllers: make(map[string]*FallbackController),
		activeConnections:   make(map[string]activeConn),
		stats: &SchedulerStats{
			layerDialCount: make(map[Layer]int64),
			layerFailCount: make(map[Layer]int64),
		},
	}
}

// RegisterFactory 注册传输工厂
func (s *StrategyScheduler) RegisterFactory(factory TransportFactory) {
	layer := factory.Layer()
	s.layerFactories[layer] = factory
	s.logger.Debug("注册传输工厂",
		zap.String("layer", layer.String()),
		zap.String("name", factory.Name()))
}

// SetLayerOrder 设置优先级顺序
func (s *StrategyScheduler) SetLayerOrder(order []Layer) {
	if len(order) == 0 {
		s.logger.Warn("空的层级顺序，使用默认顺序")
		return
	}
	s.layerOrder = order
	s.logger.Info("更新传输层优先级顺序", zap.Any("order", order))
}

// Dial 按优先级顺序尝试建立连接
// 这是核心方法，实现了 9 层策略调度
func (s *StrategyScheduler) Dial(config *DialConfig) (net.Conn, error) {
	ctx := context.Background()
	if config.Timeout > 0 {
		var cancel context.CancelFunc
		ctx, cancel = context.WithTimeout(ctx, config.Timeout)
		defer cancel()
	}

	s.logger.Info("开始 8 层策略调度连接",
		zap.String("peer_id", config.PeerID),
		zap.Int("total_layers", len(s.layerOrder)))

	// 统计
	s.stats.mu.Lock()
	s.stats.totalDials++
	s.stats.mu.Unlock()

	var lastErr error
	for i, layer := range s.layerOrder {
		factory, ok := s.layerFactories[layer]
		if !ok {
			s.logger.Debug("该传输层未注册，跳过",
				zap.String("layer", layer.String()))
			continue
		}

		s.logger.Debug("尝试第 N 层传输",
			zap.Int("index", i),
			zap.String("layer", layer.String()),
			zap.String("name", factory.Name()))

		// 统计该层拨号次数
		s.stats.mu.Lock()
		s.stats.layerDialCount[layer]++
		s.stats.mu.Unlock()

		startTime := time.Now()
		conn, err := factory.Dial(ctx, config)
		duration := time.Since(startTime)

		if err == nil {
			// 成功！
			s.stats.mu.Lock()
			s.stats.successDials++
			s.stats.mu.Unlock()

			// 记录活跃连接
			s.connMu.Lock()
			s.activeConnections[config.PeerID] = activeConn{
				conn:        conn,
				layer:       layer,
				peerID:      config.PeerID,
				established: time.Now(),
				config:      config,
			}
			s.connMu.Unlock()

			// 创建或更新降级控制器
			s.ensureFallbackController(config.PeerID, layer)

			s.logger.Info("连接建立成功",
				zap.String("layer", layer.String()),
				zap.String("name", factory.Name()),
				zap.String("peer_id", config.PeerID),
				zap.String("remote_addr", conn.RemoteAddr().String()),
				zap.Duration("duration", duration))

			// 包装连接，用于监控
			return newMonitoredConn(conn, config.PeerID, layer, s), nil
		}

		// 失败，统计
		s.stats.mu.Lock()
		s.stats.layerFailCount[layer]++
		s.stats.mu.Unlock()

		// 记录失败并继续尝试下一层
		lastErr = err
		s.logger.Warn("该传输层连接失败，尝试下一层",
			zap.String("layer", layer.String()),
			zap.Duration("duration", duration),
			zap.Error(err))
	}

	// 所有层都失败
	return nil, fmt.Errorf("所有传输层均失败，最后错误：%w", lastErr)
}

// reconnectToLayer 触发重连到指定层级
func (s *StrategyScheduler) reconnectToLayer(peerID string, toLayer Layer) {
	s.connMu.RLock()
	ac, exists := s.activeConnections[peerID]
	s.connMu.RUnlock()

	if !exists || ac.config == nil {
		s.logger.Warn("重连失败：找不到活跃连接配置", zap.String("peer_id", peerID))
		return
	}

	factory, ok := s.layerFactories[toLayer]
	if !ok {
		s.logger.Error("重连失败：找不到目标层级工厂", zap.String("layer", toLayer.String()))
		return
	}

	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	conn, err := factory.Dial(ctx, ac.config)
	if err != nil {
		s.logger.Error("降级重连失败", zap.Error(err))
		if s.OnConnectionUpdate != nil {
			s.OnConnectionUpdate(peerID, nil, err)
		}
		return
	}

	wrappedConn := newMonitoredConn(conn, peerID, toLayer, s)

	s.connMu.Lock()
	if oldAc, exists := s.activeConnections[peerID]; exists {
		oldAc.conn.Close()
	}
	s.activeConnections[peerID] = activeConn{
		conn:        wrappedConn,
		layer:       toLayer,
		peerID:      peerID,
		established: time.Now(),
		config:      ac.config,
	}
	s.connMu.Unlock()

	if s.OnConnectionUpdate != nil {
		s.OnConnectionUpdate(peerID, wrappedConn, nil)
	}
}

// ensureFallbackController 确保对端有降级控制器
func (s *StrategyScheduler) ensureFallbackController(peerID string, initialLayer Layer) {
	s.fallbackMu.Lock()
	defer s.fallbackMu.Unlock()

	if _, exists := s.fallbackControllers[peerID]; !exists {
		controller := NewFallbackController(
			initialLayer,
			func(from, to Layer) {
				// 降级回调
				s.stats.mu.Lock()
				s.stats.fallbackCount++
				s.stats.mu.Unlock()

				s.logger.Warn("链路降级",
					zap.String("peer_id", peerID),
					zap.String("from_layer", from.String()),
					zap.String("to_layer", to.String()))

				// 触发重连到新层级
				go s.reconnectToLayer(peerID, to)
			},
			func(to Layer) {
				// 恢复回调
				s.stats.mu.Lock()
				s.stats.recoveryCount++
				s.stats.mu.Unlock()

				s.logger.Info("链路恢复",
					zap.String("peer_id", peerID),
					zap.String("to_layer", to.String()))

				// 回调处理已经在 probeHighLayers 中完成并传递了新连接
			},
			s.logger,
			s, // pass scheduler to access activeConnections
		)
		s.fallbackControllers[peerID] = controller
	}
}

// RecordLatency 记录延迟（供 MonitoredConn 调用）
func (s *StrategyScheduler) RecordLatency(peerID string, success bool, duration time.Duration) {
	s.fallbackMu.RLock()
	controller, exists := s.fallbackControllers[peerID]
	s.fallbackMu.RUnlock()

	if exists {
		controller.CheckAndFallback(success, duration)
	}
}

// GetActiveLayer 获取当前活跃的传输层（用于监控）
func (s *StrategyScheduler) GetActiveLayer() Layer {
	// 返回第一个活跃连接的层级
	s.connMu.RLock()
	defer s.connMu.RUnlock()

	for _, ac := range s.activeConnections {
		return ac.layer
	}
	return LayerDirectUDP // 默认值
}

// GetAllActiveLayers 获取所有 Peer 的活跃层级（用于全局监控）
func (s *StrategyScheduler) GetAllActiveLayers() map[string]Layer {
	s.connMu.RLock()
	defer s.connMu.RUnlock()

	result := make(map[string]Layer)
	for peerID, ac := range s.activeConnections {
		result[peerID] = ac.layer
	}
	return result
}

// GetPeerLayer 获取指定 Peer 的当前层级
func (s *StrategyScheduler) GetPeerLayer(peerID string) Layer {
	s.connMu.RLock()
	defer s.connMu.RUnlock()

	if ac, exists := s.activeConnections[peerID]; exists {
		return ac.layer
	}
	return LayerDirectUDP // 默认值
}

// GetStats 获取统计信息
func (s *StrategyScheduler) GetStats() map[string]interface{} {
	s.stats.mu.RLock()
	defer s.stats.mu.RUnlock()

	layerStats := make(map[string]int64)
	for layer, count := range s.stats.layerDialCount {
		layerStats[layer.String()+"_dial"] = count
	}
	for layer, count := range s.stats.layerFailCount {
		layerStats[layer.String()+"_fail"] = count
	}

	return map[string]interface{}{
		"total_dials":    s.stats.totalDials,
		"success_dials":  s.stats.successDials,
		"fallback_count": s.stats.fallbackCount,
		"recovery_count": s.stats.recoveryCount,
		"layer_stats":    layerStats,
	}
}

// ClosePeer 关闭指定 Peer 的连接和控制器
func (s *StrategyScheduler) ClosePeer(peerID string) {
	// 关闭连接
	s.connMu.Lock()
	if ac, exists := s.activeConnections[peerID]; exists {
		ac.conn.Close()
		delete(s.activeConnections, peerID)
	}
	s.connMu.Unlock()

	// 移除降级控制器
	s.fallbackMu.Lock()
	if controller, exists := s.fallbackControllers[peerID]; exists {
		// 停止恢复探测器
		if controller.recoveryTimer != nil {
			controller.recoveryTimer.Stop()
		}
		delete(s.fallbackControllers, peerID)
	}
	s.fallbackMu.Unlock()

	s.logger.Debug("已关闭 Peer 连接和控制器",
		zap.String("peer_id", peerID))
}

// MonitoredConn 带监控的连接包装器
type MonitoredConn struct {
	net.Conn
	peerID    string
	layer     Layer
	scheduler *StrategyScheduler
}

// newMonitoredConn 创建带监控的连接
func newMonitoredConn(conn net.Conn, peerID string, layer Layer, scheduler *StrategyScheduler) *MonitoredConn {
	return &MonitoredConn{
		Conn:      conn,
		peerID:    peerID,
		layer:     layer,
		scheduler: scheduler,
	}
}

// Read 重写 Read 方法，记录延迟
func (c *MonitoredConn) Read(b []byte) (n int, err error) {
	start := time.Now()
	n, err = c.Conn.Read(b)
	duration := time.Since(start)

	// 记录成功/失败
	c.scheduler.RecordLatency(c.peerID, err == nil, duration)

	return n, err
}

// Write 重写 Write 方法，记录延迟
func (c *MonitoredConn) Write(b []byte) (n int, err error) {
	start := time.Now()
	n, err = c.Conn.Write(b)
	duration := time.Since(start)

	// 记录成功/失败
	c.scheduler.RecordLatency(c.peerID, err == nil, duration)

	return n, err
}

// FallbackController 降级控制器
type FallbackController struct {
	currentLayer    Layer              // 当前使用的层
	windowStart     time.Time          // 滑动窗口起始时间
	packetCount     int                // 总包数
	lostPacketCount int                // 丢包数
	mu              chan struct{}      // 互斥锁（用 channel 实现）
	triggerFallback func(Layer, Layer) // 降级触发回调
	triggerRecovery func(Layer)        // 恢复触发回调
	logger          *zap.Logger
	recoveryTimer   *time.Timer // 恢复探测定时器
	scheduler       *StrategyScheduler
}

const (
	// TimeoutThreshold 单次超时阈值
	TimeoutThreshold = 500 * time.Millisecond

	// PacketLossThreshold 丢包率阈值
	PacketLossThreshold = 0.10 // 10%

	// RecoveryInterval 恢复探测间隔
	RecoveryInterval = 30 * time.Second

	// SlidingWindowDuration 滑动窗口时长
	SlidingWindowDuration = 10 * time.Second
)

// NewFallbackController 创建降级控制器
func NewFallbackController(
	initialLayer Layer,
	onFallback func(Layer, Layer),
	onRecovery func(Layer),
	logger *zap.Logger,
	scheduler *StrategyScheduler,
) *FallbackController {
	fc := &FallbackController{
		currentLayer:    initialLayer,
		mu:              make(chan struct{}, 1),
		triggerFallback: onFallback,
		triggerRecovery: onRecovery,
		logger:          logger,
		scheduler:       scheduler,
	}

	// 启动恢复探测
	fc.startRecoveryProbe()

	return fc
}

// CheckAndFallback 检查是否需要降级
// 在每次连接操作后调用
func (fc *FallbackController) CheckAndFallback(success bool, duration time.Duration) {
	select {
	case fc.mu <- struct{}{}:
		defer func() { <-fc.mu }()
	default:
		// 锁被占用，说明正在处理，直接返回
		return
	}

	// 重置滑动窗口
	if time.Since(fc.windowStart) > SlidingWindowDuration {
		fc.windowStart = time.Now()
		fc.packetCount = 0
		fc.lostPacketCount = 0
	}

	// 统计
	fc.packetCount++
	if !success || duration > TimeoutThreshold {
		fc.lostPacketCount++
	}

	// 检查是否达到阈值
	if fc.packetCount >= 10 {
		lossRate := float64(fc.lostPacketCount) / float64(fc.packetCount)
		if lossRate > PacketLossThreshold {
			fc.triggerFallbackLocked()
		}
	}
}

// triggerFallbackLocked 执行降级（已持有锁）
func (fc *FallbackController) triggerFallbackLocked() {
	currentIndex := int(fc.currentLayer)
	if currentIndex >= int(LayerCount)-1 {
		// 已经是最低优先级，无法降级
		fc.logger.Warn("已是最底层级，无法降级",
			zap.String("current_layer", fc.currentLayer.String()))
		return
	}

	nextLayer := Layer(currentIndex + 1)

	// 在更新 currentLayer 之前保存旧值用于回调
	oldLayer := fc.currentLayer

	fc.logger.Warn("触发降级",
		zap.String("from_layer", oldLayer.String()),
		zap.String("to_layer", nextLayer.String()))

	fc.currentLayer = nextLayer
	fc.resetWindow()

	if fc.triggerFallback != nil {
		fc.triggerFallback(oldLayer, nextLayer)
	}

	// 重置恢复定时器
	fc.startRecoveryProbe()
}

// startRecoveryProbe 启动恢复探测
func (fc *FallbackController) startRecoveryProbe() {
	if fc.recoveryTimer != nil {
		fc.recoveryTimer.Stop()
	}

	fc.recoveryTimer = time.AfterFunc(RecoveryInterval, func() {
		fc.probeHigherLayers()
	})
}

// probeHigherLayers 探测更高层级
func (fc *FallbackController) probeHigherLayers() {
	select {
	case fc.mu <- struct{}{}:
		defer func() { <-fc.mu }()
	default:
		return
	}

	currentIndex := int(fc.currentLayer)
	if currentIndex == 0 {
		// 已经是最高优先级，无需探测
		return
	}

	// 尝试上一层
	higherLayer := Layer(currentIndex - 1)
	fc.logger.Info("探测更高层级",
		zap.String("current_layer", fc.currentLayer.String()),
		zap.String("probe_layer", higherLayer.String()))

	// 获取 PeerID 及 Config
	fc.scheduler.connMu.RLock()
	var peerID string
	var config *DialConfig
	for pid, ac := range fc.scheduler.activeConnections {
		if ac.layer == fc.currentLayer {
			peerID = pid
			config = ac.config
			break
		}
	}
	fc.scheduler.connMu.RUnlock()

	if config == nil {
		fc.logger.Warn("探测更高层级失败：找不到有效 DialConfig")
		return
	}

	factory, ok := fc.scheduler.layerFactories[higherLayer]
	if !ok {
		fc.logger.Debug("更高层级未注册工厂，跳过探测")
		return
	}

	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	conn, err := factory.Dial(ctx, config)
	if err == nil {
		fc.logger.Info("更高层级探测成功，准备切换")
		
		wrappedConn := newMonitoredConn(conn, peerID, higherLayer, fc.scheduler)
		
		fc.scheduler.connMu.Lock()
		if ac, exists := fc.scheduler.activeConnections[peerID]; exists {
			ac.conn.Close() // Close old
			ac.conn = wrappedConn
			ac.layer = higherLayer
			fc.scheduler.activeConnections[peerID] = ac
		}
		fc.scheduler.connMu.Unlock()

		if fc.scheduler.OnConnectionUpdate != nil {
			fc.scheduler.OnConnectionUpdate(peerID, wrappedConn, nil)
		}

		// 触发恢复回调
		fc.triggerRecoveryLocked(higherLayer)
	} else {
		fc.logger.Debug("更高层级探测失败", zap.Error(err))
	}
}

// triggerRecoveryLocked 执行恢复（已持有锁）
func (fc *FallbackController) triggerRecoveryLocked(higherLayer Layer) {
	fc.logger.Info("触发恢复",
		zap.String("from_layer", fc.currentLayer.String()),
		zap.String("to_layer", higherLayer.String()))

	fc.currentLayer = higherLayer
	fc.resetWindow()

	if fc.triggerRecovery != nil {
		fc.triggerRecovery(higherLayer)
	}
}

// resetWindow 重置滑动窗口
func (fc *FallbackController) resetWindow() {
	fc.windowStart = time.Now()
	fc.packetCount = 0
	fc.lostPacketCount = 0
}

// GetCurrentLayer 获取当前层级
func (fc *FallbackController) GetCurrentLayer() Layer {
	select {
	case fc.mu <- struct{}{}:
		defer func() { <-fc.mu }()
	default:
		return fc.currentLayer
	}
	return fc.currentLayer
}
