package scheduler

// This file demonstrates how to add a custom scheduler.
// To create your own:
//   1. Copy this file and rename it (e.g., weighted_rtt.go)
//   2. Implement the three PathScheduler methods
//   3. Update the init() to register with your scheduler name
//
// The scheduler will automatically appear in --list-schedulers.

import (
	"sync"

	quic "github.com/AeonDave/mp-quic-go"
)

func init() {
	Register("weighted", func() quic.PathScheduler {
		return NewWeightedScheduler()
	})
}

// WeightedScheduler is an example custom scheduler that weighs paths
// by a combination of RTT and available congestion window.
type WeightedScheduler struct {
	mu     sync.Mutex
	quotas map[quic.PathID]uint64
}

// NewWeightedScheduler creates a new weighted scheduler.
func NewWeightedScheduler() *WeightedScheduler {
	return &WeightedScheduler{
		quotas: make(map[quic.PathID]uint64),
	}
}

// SelectPath picks the path with the best weighted score.
// Score = (CongestionWindow - BytesInFlight) / (1 + SmoothedRTT_ms)
// Higher score = more capacity available per unit latency.
func (s *WeightedScheduler) SelectPath(paths []quic.SchedulerPathInfo, hasRetransmission bool) *quic.SchedulerPathInfo {
	s.mu.Lock()
	defer s.mu.Unlock()

	if len(paths) == 0 {
		return nil
	}
	if len(paths) == 1 {
		if !hasRetransmission && !paths[0].SendingAllowed {
			return nil
		}
		return &paths[0]
	}

	var best *quic.SchedulerPathInfo
	var bestScore float64 = -1

	for i := range paths {
		p := &paths[i]
		if !hasRetransmission && !p.SendingAllowed {
			continue
		}
		if p.PotentiallyFailed {
			continue
		}

		// Available window
		available := float64(0)
		if p.CongestionWindow > p.BytesInFlight {
			available = float64(p.CongestionWindow - p.BytesInFlight)
		}

		// RTT factor (ms, minimum 1 to avoid division by zero)
		rttMs := float64(1)
		if p.SmoothedRTT.Milliseconds() > 0 {
			rttMs = float64(p.SmoothedRTT.Milliseconds())
		}

		score := available / rttMs
		if score > bestScore {
			bestScore = score
			best = p
		}
	}

	return best
}

// UpdateQuota tracks per-path send counts.
func (s *WeightedScheduler) UpdateQuota(pathID quic.PathID, packetSize quic.ByteCount) {
	s.mu.Lock()
	defer s.mu.Unlock()
	s.quotas[pathID]++
}

// Reset clears all state.
func (s *WeightedScheduler) Reset() {
	s.mu.Lock()
	defer s.mu.Unlock()
	s.quotas = make(map[quic.PathID]uint64)
}
