package promptcompiler

import (
	"context"
	"fmt"
	"strings"
)

// TestLaunchSurfaces is a test-only fixture input. Production code must use
// CompileLaunchPrompt with domain facts; the policy guard rejects this helper
// outside *_test.go files.
type TestLaunchSurfaces struct {
	Prompt                string
	FreshPrompt           string
	ResumePrompt          string
	BaseInstructions      string
	DeveloperInstructions string
	SystemPrompt          string
	RuntimeCarrier        string
	ContractCarrierFile   string
	KimiInitialPrompt     string
}

// NewTestLaunchCarrier creates a sealed carrier for adapter contract tests
// without exposing a production construction path.
func NewTestLaunchCarrier(ctx context.Context, runtime string, surfaces TestLaunchSurfaces) (CompiledPrompt, error) {
	if err := contextError(ctx); err != nil {
		return CompiledPrompt{}, err
	}
	if strings.TrimSpace(runtime) == "" {
		return CompiledPrompt{}, fmt.Errorf("test launch fixture requires runtime")
	}
	carrier := launchPromptCarrier{
		Prompt: surfaces.Prompt, FreshPrompt: surfaces.FreshPrompt, ResumePrompt: surfaces.ResumePrompt,
		BaseInstructions: surfaces.BaseInstructions, DeveloperInstructions: surfaces.DeveloperInstructions, SystemPrompt: surfaces.SystemPrompt,
		RuntimeCarrier: surfaces.RuntimeCarrier, ContractCarrierFile: surfaces.ContractCarrierFile, KimiInitialPrompt: surfaces.KimiInitialPrompt,
	}
	if strings.TrimSpace(carrier.SystemPrompt) == "" {
		carrier.SystemPrompt = joinPromptSections(carrier.BaseInstructions, carrier.DeveloperInstructions)
	}
	if runtime == "kimi" && strings.TrimSpace(carrier.KimiInitialPrompt) == "" {
		carrier.KimiInitialPrompt = joinPromptSections(carrier.BaseInstructions, carrier.DeveloperInstructions, selectedFixtureTurn(carrier))
	}
	bundle := PromptBundle{SchemaVersion: SchemaVersion, EventID: "test-launch", EventType: EventFreshStart, AgentID: "test"}
	bundle.Fingerprint = fingerprintBundle(bundle, EventTurnContext)
	env := RuntimeInputEnvelope{SchemaVersion: SchemaVersion, EventID: bundle.EventID, EventType: EventFreshStart, EventKind: EventTurnContext, Bundle: &bundle, Fingerprint: fingerprintEnvelope(EventTurnContext, EventFreshStart, bundle.Fingerprint)}
	rendered := RenderedPromptPayload{Runtime: runtime, Slots: map[string]any{
		"prompt": carrier.Prompt, "freshPrompt": carrier.FreshPrompt, "resumePrompt": carrier.ResumePrompt,
		"baseInstructions": carrier.BaseInstructions, "developerInstructions": carrier.DeveloperInstructions, "systemPrompt": carrier.SystemPrompt,
		"runtimeCarrier": carrier.RuntimeCarrier, "contractCarrierFile": carrier.ContractCarrierFile, "kimiInitialPrompt": carrier.KimiInitialPrompt,
	}, RenderOrder: []string{"prompt", "freshPrompt", "resumePrompt", "baseInstructions", "developerInstructions", "runtimeCarrier"}}
	rendered.PromptSlots = PromptSlots{Prompt: carrier.Prompt, FreshPrompt: carrier.FreshPrompt, ResumePrompt: carrier.ResumePrompt, BaseInstructions: carrier.BaseInstructions, DeveloperInstructions: carrier.DeveloperInstructions, SystemPrompt: carrier.SystemPrompt, RuntimeCarrier: carrier.RuntimeCarrier, ContractCarrierFile: carrier.ContractCarrierFile, KimiInitialPrompt: carrier.KimiInitialPrompt}
	return CompiledPrompt{envelope: env, rendered: rendered, launch: &carrier}, nil
}

func selectedFixtureTurn(carrier launchPromptCarrier) string {
	if strings.TrimSpace(carrier.FreshPrompt) != "" {
		return carrier.FreshPrompt
	}
	return carrier.ResumePrompt
}

// NewTestDeliveryCarrier creates a sealed delivery carrier for transport tests.
func NewTestDeliveryCarrier(ctx context.Context, runtime, text string) (CompiledPrompt, error) {
	if err := contextError(ctx); err != nil {
		return CompiledPrompt{}, err
	}
	delivery := &DeliveryEnvelope{PayloadText: text, Fingerprint: shortFingerprint(text)}
	env := RuntimeInputEnvelope{SchemaVersion: SchemaVersion, EventID: "test-delivery", EventType: EventRoutedMessageDelivery, EventKind: EventDeliveryEnvelope, Delivery: delivery, Fingerprint: fingerprintEnvelope(EventDeliveryEnvelope, EventRoutedMessageDelivery, delivery.Fingerprint)}
	rendered := RenderedPromptPayload{Runtime: runtime, Slots: map[string]any{"deliveryText": text}, RenderOrder: []string{"deliveryText"}}
	rendered.PromptSlots.DeliveryText = text
	return CompiledPrompt{envelope: env, rendered: rendered}, nil
}
