package openai

import (
	"context"
	"fmt"
	"strings"
	"time"

	edgeservice "iop/apps/edge/internal/service"
)

func collectRunResult(ctx context.Context, stream edgeservice.RunStream, timeout time.Duration) (string, string, *openAIUsage, error) {
	if stream.Events == nil {
		return "", "", nil, fmt.Errorf("run stream unavailable")
	}
	var contentBuilder strings.Builder
	var reasoningBuilder strings.Builder
	var usage *openAIUsage
	timer := time.NewTimer(timeout)
	defer timer.Stop()
	for {
		select {
		case <-ctx.Done():
			return "", "", nil, ctx.Err()
		case <-timer.C:
			return "", "", nil, fmt.Errorf("run timed out")
		case nodeEvent, ok := <-stream.NodeEvents:
			if !ok {
				stream.NodeEvents = nil
				continue
			}
			if edgeservice.IsNodeDisconnected(nodeEvent) {
				return "", "", nil, fmt.Errorf("node disconnected")
			}
		case event, ok := <-stream.Events:
			if !ok {
				return "", "", nil, fmt.Errorf("run stream closed")
			}
			if event == nil {
				continue
			}
			switch event.GetType() {
			case "delta":
				contentBuilder.WriteString(event.GetDelta())
			case "reasoning_delta":
				reasoningBuilder.WriteString(event.GetDelta())
			case "complete":
				if u := event.GetUsage(); u != nil {
					usage = &openAIUsage{
						PromptTokens:     int(u.GetInputTokens()),
						CompletionTokens: int(u.GetOutputTokens()),
						TotalTokens:      int(u.GetInputTokens() + u.GetOutputTokens()),
					}
				}
				return contentBuilder.String(), reasoningBuilder.String(), usage, nil
			case "error", "cancelled":
				msg := event.GetError()
				if msg == "" {
					msg = event.GetMessage()
				}
				if msg == "" {
					msg = "run failed"
				}
				return "", "", nil, fmt.Errorf("%s", msg)
			}
		}
	}
}
