package promptcompiler

import (
	"strings"

	"github.com/tidbcloud/AgentTeam/desktop/internal/consts"
	"github.com/tidbcloud/AgentTeam/desktop/internal/types"
)

// RenderedSurfaceAttribution is a compiler-owned fallback attribution row.
type RenderedSurfaceAttribution struct {
	Slot   string
	Tokens int
}

// RenderedSurfaceAttributions returns named surface attribution without making
// callers parse the compatibility slot map.
func RenderedSurfaceAttributions(rendered RenderedPromptPayload) []RenderedSurfaceAttribution {
	rows := make([]RenderedSurfaceAttribution, 0, len(rendered.RenderOrder))
	for _, slot := range rendered.RenderOrder {
		text := rendered.SlotText(slot)
		if strings.TrimSpace(text) == "" {
			continue
		}
		rows = append(rows, RenderedSurfaceAttribution{Slot: strings.TrimSpace(slot), Tokens: EstimateTokens(text)})
	}
	return rows
}

// TrajectoryInputs returns compiler-authored prompt input records for launch
// attribution. Semantic surface extraction stays inside promptcompiler; the
// dispatcher only persists the typed records.
func (p CompiledPrompt) TrajectoryInputs(runtime string, eventType CompileEventType) []types.TrajectoryEntry {
	if !p.Valid() {
		return nil
	}
	components := p.components
	if len(components) > 0 {
		hasResume := false
		for _, component := range components {
			if component.Freshness == "resume" {
				hasResume = true
				break
			}
		}
		if hasResume {
			filtered := components[:0]
			for _, component := range components {
				if component.Freshness != "fresh" {
					filtered = append(filtered, component)
				}
			}
			components = filtered
		}
	}
	if len(components) == 0 {
		components = []CompiledPromptComponent{{Stage: string(p.envelope.EventKind), Freshness: "", Envelope: p.envelope, Rendered: p.rendered}}
	}
	entries := make([]types.TrajectoryEntry, 0)
	for _, component := range components {
		if strings.TrimSpace(component.Envelope.TurnID) == "" && component.Envelope.EventKind == EventThreadContract && component.Envelope.EventType == EventThreadResume {
			continue
		}
		componentEventType := component.Envelope.EventType
		for _, slot := range component.Rendered.RenderOrder {
			text := component.Rendered.SlotText(slot)
			if strings.TrimSpace(text) == "" {
				continue
			}
			kind := trajectoryPromptKind(slot, componentEventType)
			if trajectorySensitive(kind) {
				text = ""
			}
			entries = append(entries, types.TrajectoryEntry{
				Kind:       consts.ParsedEventKindPromptInput,
				Text:       text,
				PromptKind: kind,
				Runtime:    strings.TrimSpace(runtime),
				EventType:  string(componentEventType),
			})
		}
	}
	return entries
}

func trajectoryPromptKind(slot string, eventType CompileEventType) string {
	switch strings.TrimSpace(slot) {
	case "baseInstructions":
		return consts.PromptKindBaseInstructions
	case "developerInstructions":
		return consts.PromptKindDeveloperInstructions
	case "runtimeCarrier":
		return consts.PromptKindRuntimeNativeContract
	case "deliveryText":
		return consts.PromptKindDeliveryText
	case "turnInput":
		if eventType == EventResume {
			return consts.PromptKindResume
		}
		if eventType == EventDeferredContinuation {
			return consts.PromptKindDeferredContinuation
		}
		return consts.PromptKindTurnInput
	default:
		return consts.PromptKindTurnInput
	}
}

func trajectorySensitive(kind string) bool {
	switch strings.TrimSpace(kind) {
	case consts.PromptKindBaseInstructions, consts.PromptKindDeveloperInstructions, consts.PromptKindRuntimeNativeContract, consts.PromptKindResume:
		return true
	default:
		return false
	}
}
