package background

import (
	"crypto/rand"
	"fmt"
	"strings"
	"sync"
	"time"
)

// ThinkRecord is a single thinking session's result.
type ThinkRecord struct {
	ID          string    `json:"id"`
	Content     string    `json:"content"`
	Conclusions []string  `json:"conclusions"` // key takeaways
	FollowUps   []string  `json:"follow_ups"`  // questions to continue
	ToolCalls   int       `json:"tool_calls"`
	Trigger     string    `json:"trigger"` // post_chat, silence, periodic
	Timestamp   time.Time `json:"timestamp"`
}

// ThinkChain stores linked thinking records so each round
// can build on previous conclusions.
type ThinkChain struct {
	mu      sync.Mutex
	records []ThinkRecord
	maxSize int
}

// NewThinkChain creates a think chain with the given max size.
func NewThinkChain(maxSize int) *ThinkChain {
	if maxSize <= 0 {
		maxSize = 10
	}
	return &ThinkChain{
		records: make([]ThinkRecord, 0, maxSize),
		maxSize: maxSize,
	}
}

// Add appends a new think record, evicting oldest if at capacity.
func (c *ThinkChain) Add(r ThinkRecord) {
	c.mu.Lock()
	defer c.mu.Unlock()
	if len(c.records) >= c.maxSize {
		c.records = c.records[1:]
	}
	c.records = append(c.records, r)
}

// LastConclusions returns conclusions from the most recent N records.
func (c *ThinkChain) LastConclusions(n int) []string {
	c.mu.Lock()
	defer c.mu.Unlock()
	var result []string
	start := len(c.records) - n
	if start < 0 {
		start = 0
	}
	for _, r := range c.records[start:] {
		result = append(result, r.Conclusions...)
	}
	return result
}

// LastFollowUps returns follow-up questions from the single most recent record.
func (c *ThinkChain) LastFollowUps() []string {
	c.mu.Lock()
	defer c.mu.Unlock()
	if len(c.records) == 0 {
		return nil
	}
	return c.records[len(c.records)-1].FollowUps
}

// LastTopic attempts to infer a topic from recent conclusions.
func (c *ThinkChain) LastTopic() string {
	c.mu.Lock()
	defer c.mu.Unlock()
	if len(c.records) == 0 {
		return ""
	}
	// Use first conclusion line of the most recent record as topic
	for _, r := range c.records {
		for _, c := range r.Conclusions {
			if c != "" {
				runes := []rune(c)
				if len(runes) > 50 {
					return string(runes[:50]) + "..."
				}
				return c
			}
		}
	}
	return ""
}

// Size returns the current number of records in the chain.
func (c *ThinkChain) Size() int {
	c.mu.Lock()
	defer c.mu.Unlock()
	return len(c.records)
}

// extractConclusions parses the LLM thinking output to find conclusions and follow-ups.
// Looks for "结论" / "后续" markers in the content.
func extractConclusions(content string) (conclusions []string, followUps []string) {
	lines := strings.Split(content, "\n")
	inConclusions := false
	inFollowUps := false

	for _, line := range lines {
		line = strings.TrimSpace(line)

		if strings.Contains(line, "结论") && (strings.Contains(line, "💭") || strings.Contains(line, "📝") || strings.HasPrefix(line, "-")) {
			// Heuristic: this line starts a conclusions section
		}

		// Match bullet-point conclusions: lines starting with - or •
		if (strings.HasPrefix(line, "- ") || strings.HasPrefix(line, "• ")) && !inFollowUps {
			text := strings.TrimPrefix(line, "- ")
			text = strings.TrimPrefix(text, "• ")
			text = strings.TrimSpace(text)
			if text != "" && len([]rune(text)) > 2 {
				if inConclusions {
					conclusions = append(conclusions, text)
				} else {
					// Without explicit marker, treat all bullets as conclusions
					conclusions = append(conclusions, text)
				}
			}
			continue
		}

		// Detect section transitions
		if strings.Contains(line, "后续") || strings.Contains(line, "继续思考") || strings.Contains(line, "下次") {
			inFollowUps = true
			inConclusions = false
			continue
		}
		if strings.Contains(line, "结论") || strings.Contains(line, "观察") || strings.Contains(line, "记忆") {
			inConclusions = true
			inFollowUps = false
			continue
		}
	}

	// If no structured markers found, treat the whole content as a single conclusion
	if len(conclusions) == 0 {
		runes := []rune(content)
		if len(runes) > 200 {
			content = string(runes[:200]) + "..."
		}
		conclusions = []string{content}
	}

	return conclusions, followUps
}

// generateID generates a short random ID.
func generateID() string {
	b := make([]byte, 6)
	rand.Read(b)
	return fmt.Sprintf("th-%x", b)
}