package protocol

import "encoding/json"

// Agnt-specific command verbs (beyond those in go-cli-server).
const (
	VerbProxy        = "PROXY"
	VerbProxyLog     = "PROXYLOG"
	VerbCurrentPage  = "CURRENTPAGE"
	VerbTunnel       = "TUNNEL"
	VerbBrowser      = "BROWSER"
	VerbAutomation   = "AUTOMATION" // chromedp-based browser automation sessions
	VerbChaos        = "CHAOS"
	VerbDetect       = "DETECT"
	VerbOverlay      = "OVERLAY"
	VerbStatus       = "STATUS" // Full daemon status (Hub's INFO is minimal)
	VerbStore        = "STORE"
	VerbAutomate     = "AUTOMATE"      // Agent-based automation processing
	VerbAlerts       = "ALERTS"        // Process output alert queries
	VerbScript       = "SCRIPT"        // Script registry queries and control
	VerbDoctor       = "DOCTOR"        // Health check / diagnostic report
	VerbAutostart    = "AUTOSTART"     // Resolve port conflicts and resume autostart
	VerbStreamEvents = "STREAM-EVENTS" // Long-lived event stream
	VerbHook         = "HOOK"          // Claude Code hook dispatcher enqueue
	VerbIncidents    = "INCIDENTS"     // Incident inbox query + mark-read
	VerbPorts        = "PORTS"         // Listening-port inventory + orphan pgid management
)

// Agnt-specific sub-verbs (beyond those in go-cli-server).
const (
	SubVerbExec          = "EXEC"
	SubVerbToast         = "TOAST"
	SubVerbQuery         = "QUERY"
	SubVerbStats         = "STATS"
	SubVerbActivity      = "ACTIVITY"
	SubVerbOutputPreview = "OUTPUT-PREVIEW"
	SubVerbEnable        = "ENABLE"
	SubVerbDisable       = "DISABLE"
	SubVerbAddRule       = "ADD-RULE"
	SubVerbRemoveRule    = "REMOVE-RULE"
	SubVerbListRules     = "LIST-RULES"
	SubVerbPreset        = "PRESET"
	SubVerbReset         = "RESET"
	SubVerbSend          = "SEND"
	SubVerbSchedule      = "SCHEDULE"
	SubVerbCancel        = "CANCEL"
	SubVerbTasks         = "TASKS"
	SubVerbFind          = "FIND"
	SubVerbAttach        = "ATTACH"
	SubVerbURL           = "URL"           // Report detected URL from agnt run session
	SubVerbGetAll        = "GET-ALL"       // Get all entries in a scope
	SubVerbDelete        = "DELETE"        // Delete an entry from a scope
	SubVerbRunGroup      = "RUN-GROUP"     // Launch a multi-process startup group with depends_on ordering
	SubVerbProcess       = "PROCESS"       // Process a single automation task
	SubVerbBatch         = "BATCH"         // Process multiple automation tasks
	SubVerbRestart       = "RESTART"       // Restart a process or proxy
	SubVerbScreenshot    = "SCREENSHOT"    // Take screenshot in automation session
	SubVerbNavigate      = "NAVIGATE"      // Navigate to URL in automation session
	SubVerbEvaluate      = "EVALUATE"      // Evaluate JavaScript in automation session
	SubVerbReport        = "REPORT"        // Report alert matches from agnt run
	SubVerbStartupLog    = "STARTUP-LOG"   // Query startup log (successes and failures)
	SubVerbClearPorts    = "CLEAR-PORTS"   // Kill port blockers and resume autostart
	SubVerbContinue      = "CONTINUE"      // Resume autostart without killing blockers
	SubVerbAutostartRun  = "RUN"           // Run autostart from MCP InitializedHandler (non-interactive)
	SubVerbCleanOrphans  = "CLEAN-ORPHANS" // Reap orphaned process groups (PORTS verb)
)

// ProxyStartConfig represents configuration for a PROXY START command.
type ProxyStartConfig struct {
	ID          string        `json:"id"`
	TargetURL   string        `json:"target_url"`
	Port        int           `json:"port"`
	MaxLogSize  int           `json:"max_log_size,omitempty"`
	BindAddress string        `json:"bind_address,omitempty"` // "127.0.0.1" (default) or "0.0.0.0" (all interfaces)
	PublicURL   string        `json:"public_url,omitempty"`   // Public URL for tunnels (e.g., "https://abc.trycloudflare.com")
	Tunnel      *TunnelConfig `json:"tunnel,omitempty"`
}

// TunnelConfig represents configuration for starting a tunnel alongside a proxy.
type TunnelConfig struct {
	// Provider is the tunnel provider: "ngrok", "cloudflared", "tailscale", or "custom"
	Provider string `json:"provider"`
	// Command is used when Provider is "custom" - the full command to run
	Command string `json:"command,omitempty"`
	// Args are additional arguments for the tunnel command
	Args []string `json:"args,omitempty"`
	// AuthToken is the authentication token (for ngrok)
	AuthToken string `json:"auth_token,omitempty"`
	// Region is the tunnel region (optional)
	Region string `json:"region,omitempty"`
}

// LogQueryFilter represents filters for PROXYLOG QUERY command.
type LogQueryFilter struct {
	Types       []string `json:"types,omitempty"`
	Methods     []string `json:"methods,omitempty"`
	URLPattern  string   `json:"url_pattern,omitempty"`
	StatusCodes []int    `json:"status_codes,omitempty"`
	Since       string   `json:"since,omitempty"`
	Until       string   `json:"until,omitempty"`
	Limit       int      `json:"limit,omitempty"`
}

// ToastConfig represents configuration for a PROXY TOAST command.
type ToastConfig struct {
	Type     string `json:"type"`               // success, error, warning, info
	Title    string `json:"title,omitempty"`    // Toast title (optional)
	Message  string `json:"message"`            // Toast message
	Duration int    `json:"duration,omitempty"` // Duration in ms (0 for default)
}

// TunnelStartConfig represents configuration for a TUNNEL START command.
type TunnelStartConfig struct {
	ID         string `json:"id"`                    // Tunnel ID (usually same as proxy ID)
	Provider   string `json:"provider"`              // "cloudflare" or "ngrok"
	LocalPort  int    `json:"local_port"`            // Local port to tunnel
	LocalHost  string `json:"local_host,omitempty"`  // Local host (default: localhost)
	BinaryPath string `json:"binary_path,omitempty"` // Optional path to tunnel binary
	ProxyID    string `json:"proxy_id,omitempty"`    // Optional proxy ID to auto-configure public_url
}

// ChaosRuleConfig represents configuration for a CHAOS ADD-RULE command.
type ChaosRuleConfig struct {
	ID          string   `json:"id"`
	Name        string   `json:"name,omitempty"`
	Type        string   `json:"type"` // latency, out_of_order, slow_drip, disconnect, http_error, truncate, etc.
	Enabled     bool     `json:"enabled"`
	URLPattern  string   `json:"url_pattern,omitempty"`
	Methods     []string `json:"methods,omitempty"`
	Probability float64  `json:"probability,omitempty"` // 0.0-1.0, default 1.0

	// Latency config
	MinLatencyMs int `json:"min_latency_ms,omitempty"`
	MaxLatencyMs int `json:"max_latency_ms,omitempty"`
	JitterMs     int `json:"jitter_ms,omitempty"`

	// Slow-drip config
	BytesPerMs int `json:"bytes_per_ms,omitempty"`
	ChunkSize  int `json:"chunk_size,omitempty"`

	// Connection drop config
	DropAfterPercent float64 `json:"drop_after_percent,omitempty"`
	DropAfterBytes   int64   `json:"drop_after_bytes,omitempty"`

	// Error injection config
	ErrorCodes   []int  `json:"error_codes,omitempty"`
	ErrorMessage string `json:"error_message,omitempty"`

	// Truncation config
	TruncatePercent float64 `json:"truncate_percent,omitempty"`

	// Out-of-order config
	ReorderMinRequests int `json:"reorder_min_requests,omitempty"`
	ReorderMaxWaitMs   int `json:"reorder_max_wait_ms,omitempty"`

	// Stale config
	StaleDelayMs int64 `json:"stale_delay_ms,omitempty"`
}

// ChaosConfigPayload represents the full chaos configuration for SET command.
type ChaosConfigPayload struct {
	Enabled     bool               `json:"enabled"`
	Rules       []*ChaosRuleConfig `json:"rules,omitempty"`
	GlobalOdds  float64            `json:"global_odds,omitempty"`  // 0.0-1.0
	Seed        int64              `json:"seed,omitempty"`         // For reproducible chaos
	LoggingMode int                `json:"logging_mode,omitempty"` // 0=silent, 1=testing, 2=coordinated
}

// SessionRegisterConfig represents configuration for a SESSION REGISTER command.
// This extends the base hub SessionRegisterConfig with agnt-specific fields.
type SessionRegisterConfig struct {
	OverlayPath      string   `json:"overlay_path"`                 // Unix socket path for overlay
	ProjectPath      string   `json:"project_path"`                 // Directory where session was started
	Command          string   `json:"command"`                      // Command being run (e.g., "claude")
	Args             []string `json:"args,omitempty"`               // Command arguments
	SessionPGID      int      `json:"session_pgid,omitempty"`       // POSIX process group ID of the PTY child (session leader); 0 on Windows or when unavailable
	SessionJobHandle uint64   `json:"session_job_handle,omitempty"` // Windows Job Object handle for the PTY child subtree; 0 on Unix or when unavailable. Handles are per-process on Windows — this is a best-effort hint for daemon cleanup, not a stable cross-process identifier.
}

// SessionScheduleConfig represents configuration for a SESSION SCHEDULE command.
type SessionScheduleConfig struct {
	SessionCode string `json:"session_code"` // Target session
	Duration    string `json:"duration"`     // Go duration string (e.g., "5m", "1h30m")
	Message     string `json:"message"`      // Message to deliver
	ProjectPath string `json:"project_path"` // For project-scoped storage
}

// StoreGetRequest represents a STORE GET command.
type StoreGetRequest struct {
	Scope    string `json:"scope"`
	ScopeKey string `json:"scope_key"`
	Key      string `json:"key"`
}

// StoreSetRequest represents a STORE SET command.
type StoreSetRequest struct {
	Scope    string         `json:"scope"`
	ScopeKey string         `json:"scope_key"`
	Key      string         `json:"key"`
	Value    interface{}    `json:"value"`
	Metadata map[string]any `json:"metadata,omitempty"`
}

// StoreDeleteRequest represents a STORE DELETE command.
type StoreDeleteRequest struct {
	Scope    string `json:"scope"`
	ScopeKey string `json:"scope_key"`
	Key      string `json:"key"`
}

// StoreListRequest represents a STORE LIST command.
type StoreListRequest struct {
	Scope    string `json:"scope"`
	ScopeKey string `json:"scope_key"`
}

// StoreClearRequest represents a STORE CLEAR command.
type StoreClearRequest struct {
	Scope    string `json:"scope"`
	ScopeKey string `json:"scope_key"`
}

// StoreGetAllRequest represents a STORE GET_ALL command.
type StoreGetAllRequest struct {
	Scope    string `json:"scope"`
	ScopeKey string `json:"scope_key"`
}

// AutomateProcessRequest represents an AUTOMATE PROCESS command.
type AutomateProcessRequest struct {
	Type    string                 `json:"type"`    // Task type (audit_process, summarize, etc.)
	Data    map[string]interface{} `json:"data"`    // Task-specific input data
	Context map[string]interface{} `json:"context"` // Additional context
	Options AutomateOptions        `json:"options,omitempty"`
}

// AutomateOptions configures automation task processing.
type AutomateOptions struct {
	Model       string  `json:"model,omitempty"`       // Model to use (haiku, sonnet)
	MaxTokens   int     `json:"max_tokens,omitempty"`  // Max response tokens
	Temperature float64 `json:"temperature,omitempty"` // 0.0-1.0
}

// AutomateBatchRequest represents an AUTOMATE BATCH command.
type AutomateBatchRequest struct {
	Tasks []AutomateProcessRequest `json:"tasks"`
}

// AutomateProcessResponse represents the response from AUTOMATE PROCESS.
type AutomateProcessResponse struct {
	Success  bool        `json:"success"`
	Result   interface{} `json:"result,omitempty"`
	Error    string      `json:"error,omitempty"`
	Tokens   int         `json:"tokens_used"`
	CostUSD  float64     `json:"cost_usd"`
	Duration string      `json:"duration"`
}

// BrowserStartConfig represents configuration for a BROWSER START command.
type BrowserStartConfig struct {
	ID         string `json:"id,omitempty"`          // Browser ID (auto-generated if empty)
	URL        string `json:"url,omitempty"`         // URL to open
	ProxyID    string `json:"proxy_id,omitempty"`    // Proxy to use (auto-starts if needed)
	Headless   *bool  `json:"headless,omitempty"`    // Default: true
	BinaryPath string `json:"binary_path,omitempty"` // Optional Chrome path
}

// AutomationStartConfig represents configuration for an AUTOMATION START command.
type AutomationStartConfig struct {
	ID       string `json:"id,omitempty"`       // Session ID (auto-generated if empty)
	URL      string `json:"url,omitempty"`      // URL to open
	ProxyID  string `json:"proxy_id,omitempty"` // Proxy to use
	Headless *bool  `json:"headless,omitempty"` // Default: true
}

// AutomationScreenshotConfig represents configuration for an AUTOMATION SCREENSHOT command.
type AutomationScreenshotConfig struct {
	SessionID string  `json:"session_id"`         // Session ID (required)
	Type      string  `json:"type,omitempty"`     // viewport, fullpage, element, clip
	Label     string  `json:"label,omitempty"`    // Optional label for filename
	Selector  string  `json:"selector,omitempty"` // CSS selector for element type
	Viewport  string  `json:"viewport,omitempty"` // Viewport preset name
	X         float64 `json:"x,omitempty"`        // Clip X
	Y         float64 `json:"y,omitempty"`        // Clip Y
	Width     float64 `json:"width,omitempty"`    // Clip width
	Height    float64 `json:"height,omitempty"`   // Clip height
}

// AutomationNavigateConfig represents configuration for an AUTOMATION NAVIGATE command.
type AutomationNavigateConfig struct {
	SessionID string `json:"session_id"` // Session ID (required)
	URL       string `json:"url"`        // URL to navigate to (required)
}

// AutomationEvaluateConfig represents configuration for an AUTOMATION EVALUATE command.
type AutomationEvaluateConfig struct {
	SessionID string `json:"session_id"` // Session ID (required)
	Script    string `json:"script"`     // JavaScript to evaluate (required)
}

// AlertReportPayload is sent from agnt run to daemon when alert patterns match.
type AlertReportPayload struct {
	PatternID   string `json:"pattern_id"`
	Severity    string `json:"severity"`    // "error", "warning", "info"
	Category    string `json:"category"`    // "go", "dotnet", "webpack", "generic", "custom"
	Description string `json:"description"` // Pattern description
	Line        string `json:"line"`        // Matched output line
	ScriptID    string `json:"script_id"`   // Process that produced the line
	ProjectPath string `json:"project_path,omitempty"`
	Timestamp   string `json:"timestamp"` // RFC3339
}

// AlertQueryFilter filters for ALERTS QUERY.
//
// Scoping fields (Global / SessionCode / Directory) feed the session-scope
// chokepoint on the daemon side: by default the query is scoped to the
// caller's project; Global bypasses the scope (cross-project); SessionCode /
// Directory let an MCP client that is not session-bound on its daemon
// connection name the project explicitly (mirrors DirectoryFilter).
type AlertQueryFilter struct {
	Since     string `json:"since,omitempty"`      // RFC3339 or duration like "5m"
	ProcessID string `json:"process_id,omitempty"` // Filter to specific process
	Severity  string `json:"severity,omitempty"`   // Filter by severity
	Limit     int    `json:"limit,omitempty"`      // Max results (0 = all)

	Global      bool   `json:"global,omitempty"`       // Bypass session scope (cross-project)
	SessionCode string `json:"session_code,omitempty"` // Explicit session to scope to
	Directory   string `json:"directory,omitempty"`    // Explicit project directory to scope to
}

// StreamEventFilter filters events for STREAM-EVENTS command.
type StreamEventFilter struct {
	Types       []string `json:"types,omitempty"`        // Log entry types: error, http, panel_message, process, etc.
	ProxyID     string   `json:"proxy_id,omitempty"`     // Filter to specific proxy
	ProjectPath string   `json:"project_path,omitempty"` // Filter to proxies belonging to this project directory
	ProcessID   string   `json:"process_id,omitempty"`   // Filter to specific process output
	Severity    string   `json:"severity,omitempty"`     // Filter by severity: error, warning, info
	Grep        string   `json:"grep,omitempty"`         // Substring match on process output lines
	GrepStream  string   `json:"grep_stream,omitempty"`  // Filter process output stream: "stdout" or "stderr"
}

// HookPayload is sent from the `agnt hook` CLI dispatcher to the daemon when
// a Claude Code (or other agent) hook fires. The wire shape is intentionally
// tiny so the CLI can enqueue-and-exit in ~fork+write+ack time: the hook is
// synchronous from Claude's perspective and any added latency is directly
// visible to the user.
//
// `Event` is the hook name (PreToolUse, Notification, Stop, …). `Payload` is
// the raw JSON blob Claude Code wrote to stdin, preserved verbatim so
// downstream consumers can read any future fields without the CLI knowing
// about them. `Tags` carries caller-provided key/value context — project
// path, agent id, session code — so the daemon can filter and route without
// re-parsing the opaque payload.
type HookPayload struct {
	Event   string            `json:"event"`
	Payload json.RawMessage   `json:"payload,omitempty"`
	Tags    map[string]string `json:"tags,omitempty"`
}

// AutostartRunConfig is the JSON payload for AUTOSTART RUN. Sent from the MCP
// InitializedHandler to trigger project autostart in non-interactive (channel)
// mode where there is no PTY session. When NonInteractive is true, the
// port-conflict "prompt" policy falls back to "skip" with a warning because
// there is no stdin to present the prompt to.
type AutostartRunConfig struct {
	ProjectPath    string `json:"project_path"`
	NonInteractive bool   `json:"non_interactive"`
}

// IncidentQueryFilter is the request payload for INCIDENTS QUERY.
type IncidentQueryFilter struct {
	Severities   []string `json:"severities,omitempty"`   // critical/error/warning/info; empty = all
	Since        string   `json:"since,omitempty"`        // RFC3339 timestamp for lower bound
	Fingerprints []string `json:"fingerprints,omitempty"` // limit to specific fps
	Sources      []string `json:"sources,omitempty"`      // filter by Source enum values
	ProxyID      string   `json:"proxy_id,omitempty"`
	ProcessID    string   `json:"process_id,omitempty"`
	Detail       string   `json:"detail,omitempty"` // "summary" (default) | "full"
	MarkRead     bool     `json:"mark_read,omitempty"`
	Limit        int      `json:"limit,omitempty"` // 0 → 20; max 100
}

// IncidentQueryResult is the response payload for INCIDENTS QUERY.
type IncidentQueryResult struct {
	Incidents  []IncidentRecord `json:"incidents"`
	InboxStats InboxStatsRecord `json:"inbox_stats"`
	Cursor     string           `json:"cursor,omitempty"` // RFC3339 of last-seen for resumable pulls
	Truncated  bool             `json:"truncated"`
}

// IncidentRecord is the wire shape for a single incident in a query result.
type IncidentRecord struct {
	ID          string              `json:"id"`
	Fingerprint string              `json:"fingerprint"`
	FirstSeen   string              `json:"first_seen"` // RFC3339
	LastSeen    string              `json:"last_seen"`  // RFC3339
	Count       int                 `json:"count"`
	Severity    string              `json:"severity"`
	Source      string              `json:"source"`
	Category    string              `json:"category,omitempty"`
	Summary     string              `json:"summary,omitempty"`
	Payload     *string             `json:"payload,omitempty"` // set when detail="full"
	Context     IncidentContext     `json:"context,omitempty"`
	Remediation IncidentRemediation `json:"remediation,omitempty"`
	Read        bool                `json:"read"`
}

// IncidentContext is the wire shape for incident context fields.
type IncidentContext struct {
	ProcessID   string `json:"process_id,omitempty"`
	ProxyID     string `json:"proxy_id,omitempty"`
	SessionID   string `json:"session_id,omitempty"`
	ProjectPath string `json:"project_path,omitempty"`
	URL         string `json:"url,omitempty"`
	PID         int    `json:"pid,omitempty"`
	Port        int    `json:"port,omitempty"`
}

// IncidentRemediation is the wire shape for remediation hints.
type IncidentRemediation struct {
	PrimaryTool  string         `json:"primary_tool,omitempty"`
	PrimaryArgs  map[string]any `json:"primary_args,omitempty"`
	FallbackTool string         `json:"fallback_tool,omitempty"`
	SkillHint    string         `json:"skill_hint,omitempty"`
}

// InboxStatsRecord is the wire shape for inbox health summary.
type InboxStatsRecord struct {
	Critical int   `json:"critical"`
	Error    int   `json:"error"`
	Warning  int   `json:"warning"`
	Info     int   `json:"info"`
	Dropped  int64 `json:"dropped"`
	New      int   `json:"new"` // unread entries
}
