// Package runtime defines the core IOP node domain types and interfaces.
package runtime

import (
	"context"
	"errors"
	"time"
)

// SessionMode controls how a logical worker session is resolved.
type SessionMode string

const (
	SessionModeCreateIfMissing SessionMode = "create_if_missing"
	SessionModeRequireExisting SessionMode = "require_existing"
)

// CancelAction distinguishes run-cancel from session-terminate.
type CancelAction string

const (
	CancelActionCancelRun        CancelAction = "cancel_run"
	CancelActionTerminateSession CancelAction = "terminate_session"
)

// DefaultSessionID is the session key used when no session_id is provided.
const DefaultSessionID = "default"

// ErrRunCancelled is returned by adapters when a run is cancelled without terminating the session.
var ErrRunCancelled = errors.New("run cancelled")

// ExecutionSpec is the resolved, policy-applied specification for a single run.
type ExecutionSpec struct {
	RunID       string
	Adapter     string
	Target      string
	SessionID   string
	SessionMode SessionMode
	Background  bool
	Workspace   string
	Policy      map[string]any
	Input       map[string]any
	TimeoutSec  int
	Metadata    map[string]string
}

// EventType classifies a RuntimeEvent.
type EventType string

const (
	EventTypeStart          EventType = "start"
	EventTypeDelta          EventType = "delta"
	EventTypeReasoningDelta EventType = "reasoning_delta"
	EventTypeComplete       EventType = "complete"
	EventTypeError          EventType = "error"
	EventTypeCancelled      EventType = "cancelled"
)

// RuntimeEvent is a streaming execution event emitted by an Adapter.
type RuntimeEvent struct {
	RunID     string
	Type      EventType
	Delta     string
	Message   string
	Error     string
	Usage     *UsageStats
	Metadata  map[string]string
	Timestamp time.Time
}

// UsageStats reports token consumption for a completed run. ReasoningTokens and
// CachedInputTokens are populated only when the provider reports them; a zero
// value means "not reported" and downstream metric emit never estimates
// reasoning tokens from observed reasoning text.
type UsageStats struct {
	InputTokens       int
	OutputTokens      int
	ReasoningTokens   int
	CachedInputTokens int
}

// ProviderStatus is the minimal Edge-visible provider availability state.
type ProviderStatus string

const (
	ProviderStatusUnknown     ProviderStatus = "unknown"
	ProviderStatusAvailable   ProviderStatus = "available"
	ProviderStatusUnavailable ProviderStatus = "unavailable"
)

// NormalizeProviderStatus keeps provider state within the public baseline.
func NormalizeProviderStatus(status ProviderStatus) ProviderStatus {
	switch status {
	case ProviderStatusAvailable, ProviderStatusUnavailable:
		return status
	default:
		return ProviderStatusUnknown
	}
}

// Capabilities describes what an Adapter can do.
type Capabilities struct {
	AdapterName      string
	InstanceKey      string // stable registry instance key; empty for single-instance adapters
	Targets          []string
	MaxConcurrency   int
	MaxQueue         int
	QueueTimeoutMS   int
	RequestTimeoutMS int
	ProviderStatus   ProviderStatus
}

// RunRequest is the node-domain representation of an incoming run request.
type RunRequest struct {
	RunID       string
	Adapter     string
	Target      string
	SessionID   string
	SessionMode SessionMode
	Background  bool
	Workspace   string
	Policy      map[string]any
	Input       map[string]any
	TimeoutSec  int
	Metadata    map[string]string
}

// SessionTerminator is an optional interface Adapters may implement to support
// explicit session lifecycle management separate from run cancellation.
type SessionTerminator interface {
	TerminateSession(ctx context.Context, target, sessionID string) error
}

type CommandType string

const (
	CommandTypeUsageStatus     CommandType = "usage_status"
	CommandTypeCapabilities    CommandType = "capabilities"
	CommandTypeSessionList     CommandType = "session_list"
	CommandTypeTransportStatus CommandType = "transport_status"
	CommandTypeOllamaAPI       CommandType = "ollama_api"
)

type AgentUsageStatus struct {
	RawOutput       string
	DailyLimit      string
	DailyResetTime  string
	WeeklyLimit     string
	WeeklyResetTime string
	Metadata        map[string]string
}

type CommandRequest struct {
	RequestID  string
	Type       CommandType
	Adapter    string
	Target     string
	SessionID  string
	TimeoutSec int
	Metadata   map[string]string
}

type CommandResponse struct {
	RequestID   string
	Type        CommandType
	Adapter     string
	Target      string
	SessionID   string
	UsageStatus *AgentUsageStatus
	Result      map[string]string
}

type CommandHandler interface {
	HandleCommand(ctx context.Context, req CommandRequest) (CommandResponse, error)
}

// ProviderProbeResult contains the target-aware probe result of a provider.
type ProviderProbeResult struct {
	AdapterName string
	InstanceKey string
	Target      string
	Targets     []string
	Status      ProviderStatus
	Detail      string
	Metadata    map[string]string
}

// ProviderProber is an optional interface that adapters may implement
// to support active endpoint and target availability checks.
type ProviderProber interface {
	ProbeProvider(ctx context.Context, target string) (ProviderProbeResult, error)
}

// EventSink receives RuntimeEvents emitted during execution.
type EventSink interface {
	Emit(ctx context.Context, event RuntimeEvent) error
}

// Adapter executes an adapter target and streams events to a sink.
type Adapter interface {
	Name() string
	Capabilities(ctx context.Context) (Capabilities, error)
	Execute(ctx context.Context, spec ExecutionSpec, sink EventSink) error
}

// Router resolves a RunRequest into a concrete ExecutionSpec and the Adapter to execute it.
type Router interface {
	Resolve(ctx context.Context, req RunRequest) (ExecutionSpec, error)
	ResolveAdapter(ctx context.Context, req RunRequest) (ExecutionSpec, Adapter, error)
	// LookupAdapter returns an adapter by instance key or legacy type-name, preserving
	// ambiguous-lookup errors so callers can surface the exact failure reason.
	LookupAdapter(adapterName string) (Adapter, error)
	GetAdapter(adapterName string) (Adapter, bool)
}

// PolicyEngine applies and validates policies on execution specs.
type PolicyEngine interface {
	Apply(ctx context.Context, spec ExecutionSpec) (ExecutionSpec, error)
	Validate(ctx context.Context, spec ExecutionSpec) error
}

// ProviderTunnelRequest represents the node-domain request for raw provider tunnel execution.
type ProviderTunnelRequest struct {
	RunID      string
	TunnelID   string
	Adapter    string
	Target     string
	Method     string
	Path       string
	Headers    map[string]string
	Body       []byte
	Stream     bool
	TimeoutSec int
	Metadata   map[string]string
	SessionID  string
}

// ProviderTunnelFrameKind classifies a ProviderTunnelFrame.
type ProviderTunnelFrameKind string

const (
	ProviderTunnelFrameKindResponseStart ProviderTunnelFrameKind = "response_start"
	ProviderTunnelFrameKindBody          ProviderTunnelFrameKind = "body"
	ProviderTunnelFrameKindEnd           ProviderTunnelFrameKind = "end"
	ProviderTunnelFrameKindError         ProviderTunnelFrameKind = "error"
	ProviderTunnelFrameKindUsage         ProviderTunnelFrameKind = "usage"
)

// ProviderTunnelFrame carries raw provider response segments to Edge.
type ProviderTunnelFrame struct {
	RunID      string
	TunnelID   string
	Sequence   int64
	Kind       ProviderTunnelFrameKind
	StatusCode int
	Headers    map[string]string
	Body       []byte
	End        bool
	Error      string
	Usage      *UsageStats
	Metadata   map[string]string
	Timestamp  time.Time
}

// ProviderTunnelSink receives ProviderTunnelFrames emitted during provider tunnel execution.
type ProviderTunnelSink interface {
	EmitTunnelFrame(ctx context.Context, frame ProviderTunnelFrame) error
}

// ProviderTunnelAdapter is implemented by adapters that support direct HTTP/SSE raw tunneling.
type ProviderTunnelAdapter interface {
	Adapter
	TunnelProvider(ctx context.Context, req ProviderTunnelRequest, sink ProviderTunnelSink) error
}
