// Package scheduler 消息发送调度器
// Phase 1 Step 3: 自适应消息节奏控制
package scheduler

import (
	"math"
	"math/rand"
	"time"
	"unicode/utf8"
)

// MessageDisplayType 消息展示类型
type MessageDisplayType string

const (
	DisplayChat         MessageDisplayType = "chat"
	DisplayAction       MessageDisplayType = "action"
	DisplayThinking     MessageDisplayType = "thinking"
	DisplayToolProgress MessageDisplayType = "tool_progress"
	DisplaySystemInfo   MessageDisplayType = "system_info"
)

// ScheduledMessage 待发送消息
type ScheduledMessage struct {
	Type     MessageDisplayType
	Content  string
	Priority int           // 0=立即, 1=正常, 2=可延迟
	Delay    time.Duration // 相对上一条消息的延迟
}

// Complexity 消息复杂度
type Complexity int

const (
	ComplexitySimple  Complexity = iota // 问候、确认
	ComplexityNormal                    // 日常对话
	ComplexityComplex                   // 详细解答
)

// SchedulingRules 调度规则
type SchedulingRules struct {
	MinInterval         time.Duration // 最小消息间隔 200ms
	MaxInterval         time.Duration // 最大消息间隔 800ms
	MaxMessagesPerRound int           // 每轮最多消息数 5
	MaxActionsPerRound  int           // 每轮最多动作消息数 2
	ChatBeforeAction    bool          // 聊天消息先于动作
	AdaptiveRhythm      bool          // 自适应节奏
}

// DefaultRules 默认调度规则
func DefaultRules() SchedulingRules {
	return SchedulingRules{
		MinInterval:         200 * time.Millisecond,
		MaxInterval:         800 * time.Millisecond,
		MaxMessagesPerRound: 5,
		MaxActionsPerRound:  2,
		ChatBeforeAction:    true,
		AdaptiveRhythm:      true,
	}
}

// MessageScheduler 消息发送调度器
type MessageScheduler struct {
	rules SchedulingRules
	rng   *rand.Rand
}

// NewMessageScheduler 创建调度器
func NewMessageScheduler(rules SchedulingRules) *MessageScheduler {
	return &MessageScheduler{
		rules: rules,
		rng:   rand.New(rand.NewSource(time.Now().UnixNano())),
	}
}

// Schedule 调度消息发送：计算每条消息的发送延迟
func (s *MessageScheduler) Schedule(messages []ScheduledMessage) []ScheduledMessage {
	if len(messages) == 0 {
		return nil
	}

	// 1. 限制总量
	messages = s.enforceLimits(messages)

	// 2. 评估复杂度
	complexity := s.assessComplexity(messages)

	// 3. 计算基础延迟
	baseDelay := s.baseDelayForComplexity(complexity)

	// 4. 为每条消息分配延迟
	for i := range messages {
		msg := &messages[i]

		// action 消息紧跟前面的 chat
		if msg.Type == DisplayAction {
			msg.Delay = 0
			continue
		}

		// 第一条消息立即发送
		if i == 0 {
			msg.Delay = 0
			continue
		}

		// chat 消息使用带 jitter 的延迟
		jitter := baseDelay * time.Duration(0.7+0.6*s.rng.Float64())
		msg.Delay = jitter

		// 短消息适当加快
		runeCount := utf8.RuneCountInString(msg.Content)
		if runeCount < 20 {
			msg.Delay = time.Duration(math.Max(float64(msg.Delay)*0.6, float64(s.rules.MinInterval)))
		}

		// 限制在 [MinInterval, MaxInterval] 范围内
		if msg.Delay < s.rules.MinInterval {
			msg.Delay = s.rules.MinInterval
		}
		if msg.Delay > s.rules.MaxInterval {
			msg.Delay = s.rules.MaxInterval
		}
	}

	return messages
}

// enforceLimits 限制消息数量
func (s *MessageScheduler) enforceLimits(messages []ScheduledMessage) []ScheduledMessage {
	if len(messages) <= s.rules.MaxMessagesPerRound {
		return messages
	}

	var result []ScheduledMessage
	actionCount := 0
	for _, msg := range messages {
		if msg.Type == DisplayAction {
			if actionCount >= s.rules.MaxActionsPerRound {
				continue
			}
			actionCount++
		}
		result = append(result, msg)
		if len(result) >= s.rules.MaxMessagesPerRound {
			break
		}
	}
	return result
}

// assessComplexity 根据消息数量和总长度评估复杂度
func (s *MessageScheduler) assessComplexity(messages []ScheduledMessage) Complexity {
	if len(messages) <= 1 {
		return ComplexitySimple
	}

	var totalChars int
	for _, msg := range messages {
		totalChars += utf8.RuneCountInString(msg.Content)
	}

	if len(messages) <= 2 && totalChars < 60 {
		return ComplexitySimple
	}
	if len(messages) <= 3 && totalChars < 200 {
		return ComplexityNormal
	}
	return ComplexityComplex
}

// baseDelayForComplexity 根据复杂度返回基础延迟
func (s *MessageScheduler) baseDelayForComplexity(c Complexity) time.Duration {
	switch c {
	case ComplexitySimple:
		return 200 * time.Millisecond
	case ComplexityNormal:
		return 400 * time.Millisecond
	case ComplexityComplex:
		return 600 * time.Millisecond
	default:
		return 400 * time.Millisecond
	}
}
