// Package contracts defines typed data transfer objects for API communication
package contracts

import (
	"time"

	"github.com/smart-mcp-proxy/mcpproxy-go/internal/config"
)

// APIResponse is the standard wrapper for all API responses
type APIResponse struct {
	Success   bool        `json:"success"`
	Data      interface{} `json:"data,omitempty" swaggertype:"object"`
	Error     string      `json:"error,omitempty"`
	RequestID string      `json:"request_id,omitempty"`
}

// Server represents an upstream MCP server configuration and status
type Server struct {
	ID              string            `json:"id"`
	Name            string            `json:"name"`
	URL             string            `json:"url,omitempty"`
	Protocol        string            `json:"protocol"`
	Command         string            `json:"command,omitempty"`
	Args            []string          `json:"args,omitempty"`
	WorkingDir      string            `json:"working_dir,omitempty"`
	Env             map[string]string `json:"env,omitempty"`
	Headers         map[string]string `json:"headers,omitempty"`
	OAuth           *OAuthConfig      `json:"oauth,omitempty"`
	Enabled         bool              `json:"enabled"`
	Quarantined     bool              `json:"quarantined"`
	Connected       bool              `json:"connected"`
	Connecting      bool              `json:"connecting"`
	Status          string            `json:"status"`
	LastError       string            `json:"last_error,omitempty"`
	ConnectedAt     *time.Time        `json:"connected_at,omitempty"`
	LastReconnectAt *time.Time        `json:"last_reconnect_at,omitempty"`
	ReconnectCount  int               `json:"reconnect_count"`
	ToolCount       int               `json:"tool_count"`
	Created         time.Time         `json:"created"`
	Updated         time.Time         `json:"updated"`
	Isolation       *IsolationConfig  `json:"isolation,omitempty"`
	// IsolationDefaults exposes the resolved baseline values that
	// would apply when no per-server override is set. Populated on
	// list/get responses; never consumed on PATCH requests.
	IsolationDefaults *IsolationDefaults `json:"isolation_defaults,omitempty"`
	Authenticated     bool               `json:"authenticated"`                  // OAuth authentication status
	OAuthStatus       string             `json:"oauth_status,omitempty"`         // OAuth status: "authenticated", "expired", "error", "none"
	TokenExpiresAt    *time.Time         `json:"token_expires_at,omitempty"`     // When the OAuth token expires (ISO 8601)
	ToolListTokenSize int                `json:"tool_list_token_size,omitempty"` // Token size for this server's tools
	ShouldRetry       bool               `json:"should_retry,omitempty"`
	RetryCount        int                `json:"retry_count,omitempty"`
	LastRetryTime     *time.Time         `json:"last_retry_time,omitempty"`
	UserLoggedOut     bool               `json:"user_logged_out,omitempty"`  // True if user explicitly logged out (prevents auto-reconnection)
	Health            *HealthStatus      `json:"health,omitempty"`           // Unified health status calculated by the backend
	Quarantine        *QuarantineStats   `json:"quarantine,omitempty"`       // Tool quarantine metrics for this server
	ReconnectOnUse    bool               `json:"reconnect_on_use,omitempty"` // Attempt reconnection when a tool call targets this disconnected server
	// AutoApproveToolChanges mirrors config.ServerConfig.AutoApproveToolChanges
	// (MCP-2930): the per-server intent to auto-approve new/changed tools past
	// the trust baseline. Tri-state *bool — nil means "never set" (omitted from
	// the payload), so the Web UI toggle (MCP-2932) can distinguish unset from
	// an explicit false. Read-only on the GET path; PATCH/POST accept it via
	// AddServerRequest.
	AutoApproveToolChanges *bool `json:"auto_approve_tool_changes,omitempty"`
	// InitTimeout mirrors config.ServerConfig.InitTimeout (MCP-3322 / GH #760):
	// the per-server MCP `initialize` handshake deadline override. Serialized as
	// a duration string (e.g. "120s"); nil/omitted means "inherit the global
	// default". Surfaced on the GET path so clients can read back a configured
	// override; PATCH/POST accept it via AddServerRequest.
	InitTimeout  *config.Duration     `json:"init_timeout,omitempty" swaggertype:"string"`
	SecurityScan *SecurityScanSummary `json:"security_scan,omitempty"` // Latest security scan results summary
	// Spec 044 — structured diagnostic error and stable error code. Both
	// are populated when the server is in a failed state and the error
	// has been classified by internal/diagnostics. Healthy servers omit
	// these fields.
	Diagnostic *Diagnostic `json:"diagnostic,omitempty"`
	ErrorCode  string      `json:"error_code,omitempty"`
	// MCP-901 — registry provenance of an upstream that was added from a
	// registry. SourceRegistryID names the source registry (empty for
	// manually-configured servers); SourceRegistryProvenance is the trust tag
	// recorded at add time ("official/trusted" or "custom/unverified"). Both
	// are projected from config.ServerConfig so the approval/quarantine view
	// can render an "added from <registry> · unverified" origin badge. Optional
	// and omitted when empty — clients that pre-date this treat them as absent.
	SourceRegistryID         string `json:"source_registry_id,omitempty"`
	SourceRegistryProvenance string `json:"source_registry_provenance,omitempty"`
}

// Diagnostic is the REST-API representation of a classified server failure.
// It is additive: clients that pre-date spec 044 simply ignore it.
type Diagnostic struct {
	Code        string              `json:"code"`
	Severity    string              `json:"severity"`
	Cause       string              `json:"cause,omitempty"`
	DetectedAt  *time.Time          `json:"detected_at,omitempty"`
	UserMessage string              `json:"user_message,omitempty"`
	FixSteps    []DiagnosticFixStep `json:"fix_steps,omitempty"`
	DocsURL     string              `json:"docs_url,omitempty"`
}

// DiagnosticFixStep mirrors internal/diagnostics.FixStep for the REST API.
type DiagnosticFixStep struct {
	Type        string `json:"type"`
	Label       string `json:"label"`
	Command     string `json:"command,omitempty"`
	URL         string `json:"url,omitempty"`
	FixerKey    string `json:"fixer_key,omitempty"`
	Destructive bool   `json:"destructive,omitempty"`
}

// SecurityScanSummary provides a compact scan status for the server list view.
type SecurityScanSummary struct {
	LastScanAt    *time.Time     `json:"last_scan_at,omitempty"`
	RiskScore     int            `json:"risk_score"` // 0-100
	Status        string         `json:"status"`     // "clean", "warnings", "dangerous", "failed", "not_scanned", "scanning"
	FindingCounts *FindingCounts `json:"finding_counts,omitempty"`
	// Scanner coverage for the primary (baseline) scan pass — informational only.
	// Spec 077 US3 (FR-008/FR-014): Status is derived SOLELY from the
	// deterministic baseline findings; a failed Docker deep scanner no longer
	// downgrades a clean verdict. That failure is surfaced via DeepScan instead.
	ScannersRun    int `json:"scanners_run"`
	ScannersFailed int `json:"scanners_failed"`
	ScannersTotal  int `json:"scanners_total"`
	// DeepScan reports the opt-in "deep scan" layer status (Spec 077 US3),
	// SEPARATELY from the baseline verdict above. Always emitted on a computed
	// summary — when deep scan is off (the default) it reports enabled=false
	// plus any enabled-but-skipped Docker scanners. It never influences Status.
	DeepScan *DeepScanDescriptor `json:"deep_scan,omitempty"`
}

// DeepScanDescriptor reports the informational status of the opt-in "deep scan"
// layer (Docker-based scanners + source extraction) separately from the
// baseline verdict (Spec 077 US3, FR-008). A disabled, unavailable, or failed
// deep scan is a quiet note — it never downgrades an otherwise clean baseline
// and never gates approval.
//
// Invariant: when Enabled is false, Ran and Available are false and
// ScannersFailed is empty; SkippedScanners is only populated in that disabled
// state.
type DeepScanDescriptor struct {
	Enabled        bool                     `json:"enabled"`
	Ran            bool                     `json:"ran"`
	Available      bool                     `json:"available"`
	ScannersFailed []DeepScanScannerFailure `json:"scanners_failed,omitempty"`
	// SkippedScanners lists Docker scanners the user enabled that are skipped
	// because security.deep_scan.enabled is false (informational).
	SkippedScanners []string `json:"skipped_scanners,omitempty"`
}

// DeepScanScannerFailure names a single deep scanner that could not run and why.
// It is informational only and never affects the baseline verdict.
type DeepScanScannerFailure struct {
	ID     string `json:"id"`
	Reason string `json:"reason"`
}

// FindingCounts groups findings by user-facing threat category.
type FindingCounts struct {
	Dangerous int `json:"dangerous"` // Tool poisoning, active prompt injection
	Warning   int `json:"warning"`   // Rug pull, supply chain CVEs with exploits
	Info      int `json:"info"`      // Low-severity CVEs, informational
	Total     int `json:"total"`
}

// QuarantineStats represents tool quarantine metrics for a server.
type QuarantineStats struct {
	PendingCount int `json:"pending_count"` // Number of newly discovered tools awaiting approval
	ChangedCount int `json:"changed_count"` // Number of tools whose description/schema changed since approval
	BlockedCount int `json:"blocked_count"` // Number of disabled (blocked) tools
}

// OAuthConfig represents OAuth configuration for a server
type OAuthConfig struct {
	AuthURL        string            `json:"auth_url"`
	TokenURL       string            `json:"token_url"`
	ClientID       string            `json:"client_id"`
	Scopes         []string          `json:"scopes,omitempty"`
	ExtraParams    map[string]string `json:"extra_params,omitempty"`
	RedirectPort   int               `json:"redirect_port,omitempty"`
	PKCEEnabled    bool              `json:"pkce_enabled,omitempty"`
	TokenExpiresAt *time.Time        `json:"token_expires_at,omitempty"` // When the OAuth token expires
	TokenValid     bool              `json:"token_valid,omitempty"`      // Whether token is currently valid
}

// IsolationConfig represents Docker isolation configuration as it is
// exposed over the REST API. Mirrors the per-server overrides in
// config.IsolationConfig so the web UI and native tray can both edit
// these fields without reaching into config-file internals.
type IsolationConfig struct {
	Enabled     bool     `json:"enabled"`
	Image       string   `json:"image,omitempty"`
	NetworkMode string   `json:"network_mode,omitempty"`
	ExtraArgs   []string `json:"extra_args,omitempty"`
	MemoryLimit string   `json:"memory_limit,omitempty"`
	CPULimit    string   `json:"cpu_limit,omitempty"`
	WorkingDir  string   `json:"working_dir,omitempty"`
	Timeout     string   `json:"timeout,omitempty"`
}

// IsolationDefaults reports the resolved baseline Docker isolation
// settings for a server's detected runtime. UI clients (web UI, macOS
// tray) use this to render meaningful placeholders for the override
// fields — e.g. when a Python/uvx server has no Image override, the
// placeholder shows the actual image (`ghcr.io/astral-sh/uv:python3.13-...`)
// that will be used. This makes the "empty = inherit" semantic
// discoverable instead of mysterious.
//
// All fields are read-only outputs; clients must not echo them back on
// PATCH requests. They are computed from the global DockerIsolationConfig
// + the server's command (via runtime detection) on every server-list
// response.
type IsolationDefaults struct {
	RuntimeType string   `json:"runtime_type,omitempty"`
	Image       string   `json:"image,omitempty"`
	NetworkMode string   `json:"network_mode,omitempty"`
	ExtraArgs   []string `json:"extra_args,omitempty"`
	WorkingDir  string   `json:"working_dir,omitempty"`
}

// ToolAnnotation represents MCP tool behavior hints
type ToolAnnotation struct {
	Title           string `json:"title,omitempty"`
	ReadOnlyHint    *bool  `json:"readOnlyHint,omitempty"`
	DestructiveHint *bool  `json:"destructiveHint,omitempty"`
	IdempotentHint  *bool  `json:"idempotentHint,omitempty"`
	OpenWorldHint   *bool  `json:"openWorldHint,omitempty"`
}

// MCPSession represents a client session with MCPProxy
type MCPSession struct {
	ID            string     `json:"id"`
	ClientName    string     `json:"client_name,omitempty"`
	ClientVersion string     `json:"client_version,omitempty"`
	Status        string     `json:"status"`
	StartTime     time.Time  `json:"start_time"`
	EndTime       *time.Time `json:"end_time,omitempty"`
	LastActivity  time.Time  `json:"last_activity"`
	ToolCallCount int        `json:"tool_call_count"`
	TotalTokens   int        `json:"total_tokens"`
	// MCP Client Capabilities
	HasRoots     bool     `json:"has_roots,omitempty"`
	HasSampling  bool     `json:"has_sampling,omitempty"`
	Experimental []string `json:"experimental,omitempty"`
}

// Tool represents an MCP tool with its metadata
type Tool struct {
	Name           string                 `json:"name"`
	ServerName     string                 `json:"server_name"`
	Description    string                 `json:"description"`
	Schema         map[string]interface{} `json:"schema,omitempty" swaggertype:"object"`
	Usage          int                    `json:"usage"`
	LastUsed       *time.Time             `json:"last_used,omitempty"`
	Annotations    *ToolAnnotation        `json:"annotations,omitempty"`
	ApprovalStatus string                 `json:"approval_status,omitempty"`
	// Disabled mirrors ToolApprovalRecord.Disabled so per-tool enable state is
	// available without a second round-trip to the approvals endpoint. Absent
	// in the JSON when false (default) to keep responses compact.
	Disabled bool `json:"disabled,omitempty"`
	// ConfigDenied is true when the tool is denied by the server's static
	// enabled_tools / disabled_tools config. The user cannot override this toggle.
	ConfigDenied bool `json:"config_denied,omitempty"`
}

// DisabledToolStatus is the single machine-branchable reason a tool exists but
// is not callable (Spec 049). Exactly one value per locked tool. The
// classifier (classifyServerToolStatus) assigns the index-discoverable reasons
// by fixed first-match precedence (server-off → config → user → pending →
// unknown). DisabledStatusServerQuarantined is assigned separately by the
// quarantined-tool discovery pass (quarantined tools are never in the index),
// not by the classifier.
type DisabledToolStatus = string

const (
	DisabledStatusServerDisabled    DisabledToolStatus = "server_disabled"
	DisabledStatusServerQuarantined DisabledToolStatus = "server_quarantined"
	DisabledStatusByConfig          DisabledToolStatus = "disabled_by_config"
	DisabledStatusByUser            DisabledToolStatus = "disabled_by_user"
	DisabledStatusPendingApproval   DisabledToolStatus = "pending_approval"
	DisabledStatusUnknown           DisabledToolStatus = "disabled_unknown"
)

// LockedToolEntry is the lean discovery shape for a non-callable tool returned
// by retrieve_tools when include_disabled=true (Spec 049). No input schema —
// the agent only needs enough to tell the user the capability exists and why.
type LockedToolEntry struct {
	Name        string             `json:"name"`
	Server      string             `json:"server"`
	Description string             `json:"description"`
	Status      DisabledToolStatus `json:"status"`
}

// ServerToolCounts is a compact per-server rollup of tool callability,
// attached to an upstream_servers entry only when a non-callable count > 0
// (Spec 049). Zero-valued reasons are omitted to keep the payload minimal.
type ServerToolCounts struct {
	Callable         int `json:"callable"`
	DisabledByConfig int `json:"disabled_by_config,omitempty"`
	DisabledByUser   int `json:"disabled_by_user,omitempty"`
	PendingApproval  int `json:"pending_approval,omitempty"`
	ServerDisabled   int `json:"server_disabled,omitempty"`
	DisabledUnknown  int `json:"disabled_unknown,omitempty"`
}

// SearchResult represents a search result for tools
type SearchResult struct {
	Tool    Tool    `json:"tool"`
	Score   float64 `json:"score"`
	Snippet string  `json:"snippet,omitempty"`
	Matches int     `json:"matches"`
}

// ServerStats represents aggregated statistics about servers
type ServerStats struct {
	TotalServers       int                 `json:"total_servers"`
	ConnectedServers   int                 `json:"connected_servers"`
	QuarantinedServers int                 `json:"quarantined_servers"`
	TotalTools         int                 `json:"total_tools"`
	DockerContainers   int                 `json:"docker_containers"`
	TokenMetrics       *ServerTokenMetrics `json:"token_metrics,omitempty"`
}

// ServerTokenMetrics represents token usage and savings metrics
type ServerTokenMetrics struct {
	TotalServerToolListSize int            `json:"total_server_tool_list_size"` // All upstream tools combined (tokens)
	AverageQueryResultSize  int            `json:"average_query_result_size"`   // Typical retrieve_tools output (tokens)
	SavedTokens             int            `json:"saved_tokens"`                // Difference
	SavedTokensPercentage   float64        `json:"saved_tokens_percentage"`     // Percentage saved
	PerServerToolListSizes  map[string]int `json:"per_server_tool_list_sizes"`  // Token size per server
}

// UsageAggregateResponse is the GET /api/v1/activity/usage payload (Spec 069 A3).
// It is served from the actor-owned in-memory usage aggregate snapshot (never a
// per-request full-log scan, SC-005).
//
// Windowing semantics (informed by the A2 aggregate shape, data-model.md §2):
//   - The per-tool rollup (Tools) carries lifetime-cumulative metrics. `window`
//     scopes the tool LIST to tools last used within the span (by LastUsed); the
//     counts/bytes/latency themselves are lifetime totals over the aggregate's
//     retention horizon. Exact per-tool windowed counts would require per-tool
//     time buckets in the aggregate and are a deferred follow-on.
//   - The Timeline buckets are global (not per-tool); `window` trims them to the
//     requested span. Timeline is therefore not filtered by tool/server/status.
//   - tool/server/status act as membership filters on the per-tool rollup.
type UsageAggregateResponse struct {
	Window                string            `json:"window"`
	GeneratedAt           time.Time         `json:"generated_at"`
	FreshnessMs           int64             `json:"freshness_ms"` // age of the underlying snapshot in ms
	TokenSource           string            `json:"token_source"` // "bytes" (size-based proxy, FR-006)
	TokensSaved           int               `json:"tokens_saved"` // echoed from ServerTokenMetrics (FR-007)
	TokensSavedPercentage float64           `json:"tokens_saved_percentage"`
	Tools                 []UsageToolStat   `json:"tools"`
	Other                 *UsageOtherBucket `json:"other,omitempty"` // present only when the list was truncated to top-N
	Timeline              []UsageTimeBucket `json:"timeline"`
}

// UsageToolStat is the per-(server,tool) rollup row in UsageAggregateResponse.
type UsageToolStat struct {
	Server         string    `json:"server"`
	Tool           string    `json:"tool"`
	Calls          int64     `json:"calls"`
	Errors         int64     `json:"errors"`
	ErrorRate      float64   `json:"error_rate"`
	Blocked        int64     `json:"blocked"`
	TotalRespBytes int64     `json:"total_resp_bytes"`
	AvgRespBytes   *int64    `json:"avg_resp_bytes"` // null when sized_calls == 0 (only legacy 0-byte calls)
	TotalReqBytes  int64     `json:"total_req_bytes"`
	AvgReqBytes    *int64    `json:"avg_req_bytes"` // null when no sized request calls
	SizedCalls     int64     `json:"sized_calls"`   // calls with known response size (basis for avg_resp_bytes)
	P50Ms          int64     `json:"p50_ms"`
	P95Ms          int64     `json:"p95_ms"`
	LastUsed       time.Time `json:"last_used"`
}

// UsageOtherBucket folds the tail of the per-tool list beyond top-N (FR: charts
// stay readable on high-cardinality logs).
type UsageOtherBucket struct {
	ToolsFolded    int   `json:"tools_folded"`
	Calls          int64 `json:"calls"`
	TotalRespBytes int64 `json:"total_resp_bytes"`
}

// UsageTimeBucket is one timeline bar (executed calls only; blocked attempts and
// non-tool records are excluded by the aggregate).
type UsageTimeBucket struct {
	Start          time.Time `json:"start"`
	Calls          int64     `json:"calls"`
	Errors         int64     `json:"errors"`
	TotalRespBytes int64     `json:"total_resp_bytes"`
}

// LogEntry represents a single log entry
type LogEntry struct {
	Timestamp time.Time              `json:"timestamp"`
	Level     string                 `json:"level"`
	Message   string                 `json:"message"`
	Server    string                 `json:"server,omitempty"`
	Fields    map[string]interface{} `json:"fields,omitempty" swaggertype:"object"`
}

// SystemStatus represents the overall system status
type SystemStatus struct {
	Phase      string        `json:"phase"`
	Message    string        `json:"message"`
	Uptime     time.Duration `json:"uptime"`
	StartedAt  time.Time     `json:"started_at"`
	ConfigPath string        `json:"config_path"`
	LogDir     string        `json:"log_dir"`
	Runtime    RuntimeStatus `json:"runtime"`
	Servers    ServerStats   `json:"servers"`
}

// RuntimeStatus represents runtime-specific status information
type RuntimeStatus struct {
	Version        string    `json:"version"`
	GoVersion      string    `json:"go_version"`
	BuildTime      string    `json:"build_time,omitempty"`
	IndexStatus    string    `json:"index_status"`
	StorageStatus  string    `json:"storage_status"`
	LastConfigLoad time.Time `json:"last_config_load"`
}

// ToolCallRequest represents a request to call a tool
type ToolCallRequest struct {
	ToolName string                 `json:"tool_name"`
	Args     map[string]interface{} `json:"args" swaggertype:"object"`
}

// ToolCallResponse represents the response from a tool call
type ToolCallResponse struct {
	ToolName   string      `json:"tool_name"`
	ServerName string      `json:"server_name"`
	Result     interface{} `json:"result" swaggertype:"object"`
	Error      string      `json:"error,omitempty"`
	Duration   string      `json:"duration"`
	Timestamp  time.Time   `json:"timestamp"`
}

// Event represents a system event for SSE streaming
type Event struct {
	Type      string                 `json:"type"`
	Data      interface{}            `json:"data" swaggertype:"object"`
	Server    string                 `json:"server,omitempty"`
	Timestamp time.Time              `json:"timestamp"`
	Metadata  map[string]interface{} `json:"metadata,omitempty" swaggertype:"object"`
}

// API Request/Response DTOs

// GetServersResponse is the response for GET /api/v1/servers
type GetServersResponse struct {
	Servers []Server    `json:"servers"`
	Stats   ServerStats `json:"stats"`
}

// GetServerToolsResponse is the response for GET /api/v1/servers/{id}/tools
type GetServerToolsResponse struct {
	ServerName string `json:"server_name"`
	Tools      []Tool `json:"tools"`
	Count      int    `json:"count"`
}

// GlobalToolsStats is the aggregate rollup shown on the global tools page
// (spec 050). Disabled counts a tool that is user-disabled OR config-denied;
// Enabled = Total - Disabled; PendingApproval counts pending/changed approval.
type GlobalToolsStats struct {
	Total           int `json:"total"`
	Enabled         int `json:"enabled"`
	Disabled        int `json:"disabled"`
	PendingApproval int `json:"pending_approval"`
}

// GlobalToolsResponse is the response for GET /api/v1/tools — every tool from
// every configured server (including disabled servers and disabled/
// config-denied tools), enriched with approval state and usage. Partial is set
// when one or more servers could not be read; the list still contains every
// tool that could be gathered.
type GlobalToolsResponse struct {
	Tools         []Tool           `json:"tools"`
	Stats         GlobalToolsStats `json:"stats"`
	Partial       bool             `json:"partial,omitempty"`
	FailedServers []string         `json:"failed_servers,omitempty"`
}

// SearchToolsResponse is the response for GET /api/v1/index/search
type SearchToolsResponse struct {
	Query   string         `json:"query"`
	Results []SearchResult `json:"results"`
	Total   int            `json:"total"`
	Took    string         `json:"took"`
}

// GetServerLogsResponse is the response for GET /api/v1/servers/{id}/logs
type GetServerLogsResponse struct {
	ServerName string     `json:"server_name"`
	Logs       []LogEntry `json:"logs"`
	Count      int        `json:"count"`
}

// ServerActionResponse is the response for server enable/disable/restart actions
type ServerActionResponse struct {
	Server  string `json:"server"`
	Action  string `json:"action"`
	Success bool   `json:"success"`
	Async   bool   `json:"async,omitempty"`
}

// QuarantinedServersResponse is the response for quarantined servers
type QuarantinedServersResponse struct {
	Servers []Server `json:"servers"`
	Count   int      `json:"count"`
}

// Secret management DTOs

// Ref represents a reference to a secret value
type Ref struct {
	Type     string `json:"type"`     // "env", "keyring", etc.
	Name     string `json:"name"`     // The secret name/key
	Original string `json:"original"` // Original reference string like "${env:API_KEY}"
}

// MigrationCandidate represents a potential secret that could be migrated to secure storage
type MigrationCandidate struct {
	Field      string  `json:"field"`      // Field path in configuration
	Value      string  `json:"value"`      // Masked value for display
	Suggested  string  `json:"suggested"`  // Suggested secret reference
	Confidence float64 `json:"confidence"` // Confidence score (0.0 to 1.0)
}

// MigrationAnalysis represents the result of analyzing configuration for potential secrets
type MigrationAnalysis struct {
	Candidates []MigrationCandidate `json:"candidates"`
	TotalFound int                  `json:"total_found"`
}

// GetRefsResponse is the response for GET /api/v1/secrets/refs
type GetRefsResponse struct {
	Refs []Ref `json:"refs"`
}

// GetMigrationAnalysisResponse is the response for POST /api/v1/secrets/migrate
type GetMigrationAnalysisResponse struct {
	Analysis MigrationAnalysis `json:"analysis"`
}

// Diagnostics types

// DiagnosticIssue represents a single diagnostic issue
type DiagnosticIssue struct {
	Type      string                 `json:"type"`                                    // error, warning, info
	Category  string                 `json:"category"`                                // oauth, connection, secrets, config
	Server    string                 `json:"server,omitempty"`                        // Associated server (if any)
	Title     string                 `json:"title"`                                   // Short title
	Message   string                 `json:"message"`                                 // Detailed message
	Timestamp time.Time              `json:"timestamp"`                               // When detected
	Severity  string                 `json:"severity"`                                // critical, high, medium, low
	Metadata  map[string]interface{} `json:"metadata,omitempty" swaggertype:"object"` // Additional context
}

// MissingSecret represents an unresolved secret reference
type MissingSecret struct {
	Name      string `json:"name"`      // Variable/secret name
	Reference string `json:"reference"` // Original reference (e.g., "${env:API_KEY}")
	Server    string `json:"server"`    // Which server needs it
	Type      string `json:"type"`      // env, keyring, etc.
}

// DiagnosticsResponse represents the aggregated diagnostics
type DiagnosticsResponse struct {
	UpstreamErrors  []DiagnosticIssue `json:"upstream_errors"`
	OAuthRequired   []string          `json:"oauth_required"` // Server names
	MissingSecrets  []MissingSecret   `json:"missing_secrets"`
	RuntimeWarnings []DiagnosticIssue `json:"runtime_warnings"`
	TotalIssues     int               `json:"total_issues"`
	LastUpdated     time.Time         `json:"last_updated"`
}

// Diagnostics represents aggregated health information from all MCPProxy components.
// This is the new unified diagnostics format for the management service.
type Diagnostics struct {
	TotalIssues       int                       `json:"total_issues"`
	UpstreamErrors    []UpstreamError           `json:"upstream_errors"`
	OAuthRequired     []OAuthRequirement        `json:"oauth_required"`
	OAuthIssues       []OAuthIssue              `json:"oauth_issues"`    // OAuth parameter mismatches
	MissingSecrets    []MissingSecretInfo       `json:"missing_secrets"` // Renamed to avoid conflict
	RuntimeWarnings   []string                  `json:"runtime_warnings"`
	DeprecatedConfigs []DeprecatedConfigWarning `json:"deprecated_configs,omitempty"` // Deprecated config fields found
	DockerStatus      *DockerStatus             `json:"docker_status,omitempty"`
	Timestamp         time.Time                 `json:"timestamp"`
}

// DeprecatedConfigWarning represents a deprecated configuration field found in the config file.
type DeprecatedConfigWarning struct {
	Field       string `json:"field"`
	Message     string `json:"message"`
	Replacement string `json:"replacement,omitempty"`
}

// UpstreamError represents a connection or runtime error from an upstream MCP server.
type UpstreamError struct {
	ServerName   string    `json:"server_name"`
	ErrorMessage string    `json:"error_message"`
	Timestamp    time.Time `json:"timestamp"`
}

// OAuthRequirement represents an OAuth authentication requirement for a server.
type OAuthRequirement struct {
	ServerName string     `json:"server_name"`
	State      string     `json:"state"`
	ExpiresAt  *time.Time `json:"expires_at,omitempty"`
	Message    string     `json:"message"`
}

// OAuthIssue represents an OAuth configuration issue (e.g., missing parameters).
type OAuthIssue struct {
	ServerName       string   `json:"server_name"`
	Issue            string   `json:"issue"`
	Error            string   `json:"error"`
	MissingParams    []string `json:"missing_params,omitempty"`
	Resolution       string   `json:"resolution"`
	DocumentationURL string   `json:"documentation_url,omitempty"`
}

// MissingSecretInfo represents a secret referenced in configuration but not found.
// This is used by the new Diagnostics type to avoid field name conflicts.
type MissingSecretInfo struct {
	SecretName string   `json:"secret_name"`
	UsedBy     []string `json:"used_by"`
}

// DockerStatus represents the availability of Docker daemon for stdio server isolation.
type DockerStatus struct {
	Available bool   `json:"available"`
	Version   string `json:"version,omitempty"`
	Error     string `json:"error,omitempty"`
}

// AuthStatus represents detailed OAuth authentication status for a single server.
type AuthStatus struct {
	ServerName string     `json:"server_name"`
	State      string     `json:"state"`
	ExpiresAt  *time.Time `json:"expires_at,omitempty"`
	TokenType  string     `json:"token_type,omitempty"`
	Scopes     []string   `json:"scopes,omitempty"`
	Message    string     `json:"message"`
}

// OAuthStartResponse is returned by POST /api/v1/servers/{id}/login when OAuth flow starts successfully.
// Spec 020: OAuth Login Error Feedback
type OAuthStartResponse struct {
	Success       bool   `json:"success"`                 // Always true for successful start
	ServerName    string `json:"server_name"`             // Name of the server being authenticated
	CorrelationID string `json:"correlation_id"`          // UUID for tracking this flow
	AuthURL       string `json:"auth_url,omitempty"`      // Authorization URL (always included for manual use)
	BrowserOpened bool   `json:"browser_opened"`          // Whether browser launch succeeded
	BrowserError  string `json:"browser_error,omitempty"` // Error message if browser launch failed
	Message       string `json:"message"`                 // Human-readable status message
}

// OAuthValidationError is returned for pre-flight validation failures before OAuth is attempted.
// Returned with HTTP 400.
// Implements the error interface so it can be returned as an error while carrying structured data.
// Spec 020: OAuth Login Error Feedback
type OAuthValidationError struct {
	Success          bool     `json:"success"`                     // Always false
	ErrorType        string   `json:"error_type"`                  // Category of validation failure
	ServerName       string   `json:"server_name"`                 // Requested server name
	Message          string   `json:"message"`                     // Human-readable error description
	Suggestion       string   `json:"suggestion"`                  // Actionable remediation hint
	AvailableServers []string `json:"available_servers,omitempty"` // List of valid server names (for server_not_found)
	CorrelationID    string   `json:"correlation_id,omitempty"`    // Existing flow ID (for flow_in_progress)
}

// Error implements the error interface for OAuthValidationError.
func (e *OAuthValidationError) Error() string {
	return e.Message
}

// NewOAuthValidationError creates a new OAuthValidationError with the given parameters.
func NewOAuthValidationError(serverName, errorType, message, suggestion string) *OAuthValidationError {
	return &OAuthValidationError{
		Success:    false,
		ServerName: serverName,
		ErrorType:  errorType,
		Message:    message,
		Suggestion: suggestion,
	}
}

// OAuthFlowError is returned for OAuth runtime failures (after validation passes but before browser opens).
// Examples: metadata discovery failure, DCR failure, authorization URL construction failure.
// Implements the error interface so it can be returned as an error while carrying structured data.
// Spec 020: OAuth Login Error Feedback
type OAuthFlowError struct {
	Success       bool               `json:"success"`           // Always false
	ErrorType     string             `json:"error_type"`        // Category of OAuth runtime failure
	ErrorCode     string             `json:"error_code"`        // Machine-readable error code (e.g., OAUTH_NO_METADATA)
	ServerName    string             `json:"server_name"`       // Server that failed OAuth
	CorrelationID string             `json:"correlation_id"`    // Flow tracking ID for log correlation
	RequestID     string             `json:"request_id"`        // HTTP request ID (from PR #237)
	Message       string             `json:"message"`           // Human-readable error description
	Details       *OAuthErrorDetails `json:"details,omitempty"` // Structured discovery/failure details
	Suggestion    string             `json:"suggestion"`        // Actionable remediation hint
	DebugHint     string             `json:"debug_hint"`        // CLI command for log lookup
}

// Error implements the error interface for OAuthFlowError.
func (e *OAuthFlowError) Error() string {
	return e.Message
}

// NewOAuthFlowError creates a new OAuthFlowError with the given parameters.
func NewOAuthFlowError(serverName, errorType, errorCode, message, suggestion string) *OAuthFlowError {
	return &OAuthFlowError{
		Success:    false,
		ServerName: serverName,
		ErrorType:  errorType,
		ErrorCode:  errorCode,
		Message:    message,
		Suggestion: suggestion,
		DebugHint:  "For logs: mcpproxy upstream logs " + serverName,
	}
}

// OAuthErrorDetails contains structured discovery/failure details for OAuth errors.
type OAuthErrorDetails struct {
	ServerURL                   string          `json:"server_url"`
	ProtectedResourceMetadata   *MetadataStatus `json:"protected_resource_metadata,omitempty"`
	AuthorizationServerMetadata *MetadataStatus `json:"authorization_server_metadata,omitempty"`
	DCRStatus                   *DCRStatus      `json:"dcr_status,omitempty"`
}

// MetadataStatus represents the status of OAuth metadata discovery.
type MetadataStatus struct {
	Found                bool     `json:"found"`
	URLChecked           string   `json:"url_checked"`
	Error                string   `json:"error,omitempty"`
	AuthorizationServers []string `json:"authorization_servers,omitempty"`
}

// DCRStatus represents the status of Dynamic Client Registration.
type DCRStatus struct {
	Attempted  bool   `json:"attempted"`
	Success    bool   `json:"success"`
	StatusCode int    `json:"status_code,omitempty"`
	Error      string `json:"error,omitempty"`
}

// OAuth validation error type constants
const (
	OAuthValidationServerNotFound    = "server_not_found"
	OAuthValidationServerDisabled    = "server_disabled"
	OAuthValidationServerQuarantined = "server_quarantined"
	OAuthValidationNotSupported      = "oauth_not_supported"
	OAuthValidationFlowInProgress    = "flow_in_progress"
)

// OAuth flow error type constants
const (
	OAuthErrorMetadataMissing  = "oauth_metadata_missing"
	OAuthErrorMetadataInvalid  = "oauth_metadata_invalid"
	OAuthErrorResourceMismatch = "oauth_resource_mismatch"
	OAuthErrorClientIDRequired = "oauth_client_id_required"
	OAuthErrorDCRFailed        = "oauth_dcr_failed"
	OAuthErrorFlowFailed       = "oauth_flow_failed"
)

// OAuth flow error code constants (machine-readable)
const (
	OAuthCodeNoMetadata       = "OAUTH_NO_METADATA"
	OAuthCodeBadMetadata      = "OAUTH_BAD_METADATA"
	OAuthCodeResourceMismatch = "OAUTH_RESOURCE_MISMATCH"
	OAuthCodeNoClientID       = "OAUTH_NO_CLIENT_ID"
	OAuthCodeDCRFailed        = "OAUTH_DCR_FAILED"
	OAuthCodeFlowFailed       = "OAUTH_FLOW_FAILED"
)

// OAuth Authentication State Constants
const (
	AuthStateAuthenticated   = "authenticated"
	AuthStateUnauthenticated = "unauthenticated"
	AuthStateExpired         = "expired"
	AuthStateRefreshing      = "refreshing"
)

// Tool Call History types

// TokenMetrics represents token usage statistics for a tool call
type TokenMetrics struct {
	InputTokens     int     `json:"input_tokens"`               // Tokens in the request
	OutputTokens    int     `json:"output_tokens"`              // Tokens in the response
	TotalTokens     int     `json:"total_tokens"`               // Total tokens (input + output)
	Model           string  `json:"model"`                      // Model used for tokenization
	Encoding        string  `json:"encoding"`                   // Encoding used (e.g., cl100k_base)
	EstimatedCost   float64 `json:"estimated_cost,omitempty"`   // Optional cost estimate
	TruncatedTokens int     `json:"truncated_tokens,omitempty"` // Tokens removed by truncation
	WasTruncated    bool    `json:"was_truncated"`              // Whether response was truncated
}

// ToolCallRecord represents a single recorded tool call with full context
type ToolCallRecord struct {
	ID               string                 `json:"id"`                                      // Unique identifier
	ServerID         string                 `json:"server_id"`                               // Server identity hash
	ServerName       string                 `json:"server_name"`                             // Human-readable server name
	ToolName         string                 `json:"tool_name"`                               // Tool name (without server prefix)
	Arguments        map[string]interface{} `json:"arguments" swaggertype:"object"`          // Tool arguments
	Response         interface{}            `json:"response,omitempty" swaggertype:"object"` // Tool response (success only)
	Error            string                 `json:"error,omitempty"`                         // Error message (failure only)
	Duration         int64                  `json:"duration"`                                // Duration in nanoseconds
	Timestamp        time.Time              `json:"timestamp"`                               // When the call was made
	ConfigPath       string                 `json:"config_path"`                             // Active config file path
	RequestID        string                 `json:"request_id,omitempty"`                    // Request correlation ID
	Metrics          *TokenMetrics          `json:"metrics,omitempty"`                       // Token usage metrics (nil for older records)
	ParentCallID     string                 `json:"parent_call_id,omitempty"`                // Links nested calls to parent code_execution
	ExecutionType    string                 `json:"execution_type,omitempty"`                // "direct" or "code_execution"
	MCPSessionID     string                 `json:"mcp_session_id,omitempty"`                // MCP session identifier
	MCPClientName    string                 `json:"mcp_client_name,omitempty"`               // MCP client name from InitializeRequest
	MCPClientVersion string                 `json:"mcp_client_version,omitempty"`            // MCP client version
	Annotations      *ToolAnnotation        `json:"annotations,omitempty"`                   // Tool behavior hints snapshot
}

// GetToolCallsResponse is the response for GET /api/v1/tool-calls
type GetToolCallsResponse struct {
	ToolCalls []ToolCallRecord `json:"tool_calls"`
	Total     int              `json:"total"`
	Limit     int              `json:"limit"`
	Offset    int              `json:"offset"`
}

// GetToolCallDetailResponse is the response for GET /api/v1/tool-calls/{id}
type GetToolCallDetailResponse struct {
	ToolCall ToolCallRecord `json:"tool_call"`
}

// GetServerToolCallsResponse is the response for GET /api/v1/servers/{name}/tool-calls
type GetServerToolCallsResponse struct {
	ServerName string           `json:"server_name"`
	ToolCalls  []ToolCallRecord `json:"tool_calls"`
	Total      int              `json:"total"`
}

// GetSessionsResponse is the response for GET /api/v1/sessions
type GetSessionsResponse struct {
	Sessions []MCPSession `json:"sessions"`
	Total    int          `json:"total"`
	Limit    int          `json:"limit"`
	Offset   int          `json:"offset"`
}

// GetSessionDetailResponse is the response for GET /api/v1/sessions/{id}
type GetSessionDetailResponse struct {
	Session MCPSession `json:"session"`
}

// Configuration management types

// ValidationError represents a single configuration validation error
type ValidationError struct {
	Field   string `json:"field"`
	Message string `json:"message"`
}

// ConfigApplyResult represents the result of applying a configuration change
type ConfigApplyResult struct {
	Success            bool              `json:"success"`
	AppliedImmediately bool              `json:"applied_immediately"`
	RequiresRestart    bool              `json:"requires_restart"`
	RestartReason      string            `json:"restart_reason,omitempty"`
	ValidationErrors   []ValidationError `json:"validation_errors,omitempty"`
	ChangedFields      []string          `json:"changed_fields,omitempty"`
}

// GetConfigResponse is the response for GET /api/v1/config
type GetConfigResponse struct {
	Config     interface{} `json:"config" swaggertype:"object"` // The configuration object
	ConfigPath string      `json:"config_path"`                 // Path to config file
}

// ValidateConfigRequest is the request for POST /api/v1/config/validate
type ValidateConfigRequest struct {
	Config interface{} `json:"config" swaggertype:"object"` // The configuration to validate
}

// ValidateConfigResponse is the response for POST /api/v1/config/validate
type ValidateConfigResponse struct {
	Valid  bool              `json:"valid"`
	Errors []ValidationError `json:"errors,omitempty"`
}

// ApplyConfigRequest is the request for POST /api/v1/config/apply
type ApplyConfigRequest struct {
	Config interface{} `json:"config" swaggertype:"object"` // The new configuration to apply
}

// Tool call replay types

// ReplayToolCallRequest is the request for POST /api/v1/tool-calls/{id}/replay
type ReplayToolCallRequest struct {
	Arguments map[string]interface{} `json:"arguments" swaggertype:"object"` // Modified arguments for replay
}

// ReplayToolCallResponse is the response for POST /api/v1/tool-calls/{id}/replay
type ReplayToolCallResponse struct {
	Success      bool           `json:"success"`
	NewCallID    string         `json:"new_call_id"`     // ID of the newly created call
	NewToolCall  ToolCallRecord `json:"new_tool_call"`   // The new tool call record
	ReplayedFrom string         `json:"replayed_from"`   // Original call ID
	Error        string         `json:"error,omitempty"` // Error if replay failed
}

// Registry browsing types (Phase 7)

// Registry represents an MCP server registry
type Registry struct {
	ID          string      `json:"id"`
	Name        string      `json:"name"`
	Description string      `json:"description"`
	URL         string      `json:"url"`
	ServersURL  string      `json:"servers_url,omitempty"`
	Tags        []string    `json:"tags,omitempty"`
	Protocol    string      `json:"protocol,omitempty"`
	Count       interface{} `json:"count,omitempty" swaggertype:"primitive,string"` // number or string
	// Provenance is the trust tag (MCP-866): "official/trusted" for built-in
	// defaults, "custom/unverified" for user-added registries.
	Provenance string `json:"provenance,omitempty"`
	// Trusted indicates whether this is an official, shipped-by-default
	// registry. Trust is derived from membership in the default set, never
	// from self-assertion in config.
	Trusted bool `json:"trusted"`
}

// RepositoryInfo represents detected repository type information
type RepositoryInfo struct {
	NPM *NPMPackageInfo `json:"npm,omitempty"`
	// Future: PyPI, Docker Hub, etc.
}

// NPMPackageInfo represents NPM package information
type NPMPackageInfo struct {
	Exists     bool   `json:"exists"`
	InstallCmd string `json:"install_cmd"`
}

// RepositoryServer represents an MCP server from a registry
type RepositoryServer struct {
	ID             string          `json:"id"`
	Name           string          `json:"name"`
	Description    string          `json:"description"`
	URL            string          `json:"url,omitempty"`             // MCP endpoint for remote servers only
	SourceCodeURL  string          `json:"source_code_url,omitempty"` // Source repository URL
	InstallCmd     string          `json:"install_cmd,omitempty"`     // Installation command
	ConnectURL     string          `json:"connect_url,omitempty"`     // Alternative connection URL
	UpdatedAt      string          `json:"updated_at,omitempty"`
	CreatedAt      string          `json:"created_at,omitempty"`
	Registry       string          `json:"registry,omitempty"`        // Which registry this came from
	RepositoryInfo *RepositoryInfo `json:"repository_info,omitempty"` // Detected package info
}

// GetRegistriesResponse is the response for GET /api/v1/registries
type GetRegistriesResponse struct {
	Registries []Registry `json:"registries"`
	Total      int        `json:"total"`
}

// RegistryCacheInfo describes how fresh a registry search result is. AgeSeconds
// is the age of the cached server list (0 for a freshly fetched result); Stale
// is true once the cache entry has passed its TTL but is still served pending a
// manual refresh (FR-007).
type RegistryCacheInfo struct {
	AgeSeconds float64 `json:"age_seconds"`
	Stale      bool    `json:"stale"`
}

// RegistryUnavailable marks a registry that could not be queried — e.g. it
// requires an API key that is not configured. The overall search still
// succeeds; this block makes the registry's unavailability visible (FR-008).
type RegistryUnavailable struct {
	Reason string `json:"reason"`
}

// SearchRegistryServersResponse is the response for GET /api/v1/registries/{id}/servers
type SearchRegistryServersResponse struct {
	RegistryID  string               `json:"registry_id"`
	Servers     []RepositoryServer   `json:"servers"`
	Total       int                  `json:"total"`
	Query       string               `json:"query,omitempty"`
	Tag         string               `json:"tag,omitempty"`
	Cache       *RegistryCacheInfo   `json:"cache,omitempty"`
	Unavailable *RegistryUnavailable `json:"unavailable,omitempty"`
}

// RefreshRegistryResponse is the response for POST /api/v1/registries/{id}/refresh.
type RefreshRegistryResponse struct {
	RegistryID string `json:"registry_id"`
	Cleared    int    `json:"cleared"` // number of cached entries dropped
}

// AddFromRegistryRequest is the optional POST body for adding an upstream from
// a registry reference (spec 070, POST /registries/{id}/servers/{serverId}/add).
// The registry id + server id come from the URL path; this body carries only
// the optional overrides. The client never sends a config blob — the server
// re-derives the runnable config from the registry entry (CN-001 / security
// decision D1), so command/args/url and the quarantine flag cannot be smuggled.
type AddFromRegistryRequest struct {
	Name    string            `json:"name,omitempty"`    // optional name override
	Env     map[string]string `json:"env,omitempty"`     // overrides + required-input values
	Enabled *bool             `json:"enabled,omitempty"` // defaults to true when nil
}

// AddedServerSummary is the persisted-server view returned on a successful
// add-from-registry. It is intentionally a slim, stable projection of the
// re-derived config.ServerConfig (not the full struct) so the cross-surface
// contract does not leak unrelated config fields.
type AddedServerSummary struct {
	Name        string   `json:"name"`
	Protocol    string   `json:"protocol"`
	Command     string   `json:"command,omitempty"`
	Args        []string `json:"args,omitempty"`
	URL         string   `json:"url,omitempty"`
	Enabled     bool     `json:"enabled"`
	Quarantined bool     `json:"quarantined"`
}

// AddFromRegistryData is the success `data` payload for add-from-registry.
type AddFromRegistryData struct {
	Server AddedServerSummary `json:"server"`
}

// RegistryAddError carries the stable cross-surface failure code for an
// add-from-registry attempt (spec 070 CN-001). Every surface (REST, MCP, CLI)
// reports the same Code so a given failure reads identically everywhere.
// MissingInputs is populated only for code == "missing_required_input" so the
// caller can name the exact --env keys the user must supply (FR-003).
type RegistryAddError struct {
	Code          string   `json:"code"`
	Message       string   `json:"message"`
	MissingInputs []string `json:"missing_inputs,omitempty"`
}

// AddRegistrySourceRequest is the POST body for adding a user-supplied registry
// source (MCP-866, POST /api/v1/registries). Provenance is NOT part of the
// request — the server always tags an added source "custom".
type AddRegistrySourceRequest struct {
	URL      string `json:"url"`                // required https registry URL
	Protocol string `json:"protocol,omitempty"` // defaults to modelcontextprotocol/registry
	ID       string `json:"id,omitempty"`       // derived from the host when empty
	Name     string `json:"name,omitempty"`     // defaults to the id
}

// EditRegistrySourceRequest is the PUT body for editing a user-added custom
// registry (MCP-1072, PUT /api/v1/registries/{id}). All fields are optional;
// an empty field leaves the existing value unchanged.
type EditRegistrySourceRequest struct {
	Name       string `json:"name,omitempty"`        // new display name
	URL        string `json:"url,omitempty"`         // new base/servers https URL
	ServersURL string `json:"servers_url,omitempty"` // explicit servers-collection URL
}

// RegistrySummary is a slim, stable projection of a registry, including its
// provenance/trust so surfaces can flag third-party sources (MCP-866).
type RegistrySummary struct {
	ID         string `json:"id"`
	Name       string `json:"name"`
	URL        string `json:"url,omitempty"`
	ServersURL string `json:"servers_url,omitempty"`
	Protocol   string `json:"protocol,omitempty"`
	Provenance string `json:"provenance,omitempty"`
	Trusted    bool   `json:"trusted"`
}

// AddRegistrySourceData is the success `data` payload for add-source.
type AddRegistrySourceData struct {
	Registry RegistrySummary `json:"registry"`
}

// RemoveRegistrySourceData is the success `data` payload for remove-source
// (MCP-1057, DELETE /api/v1/registries/{id}). It echoes the removed registry.
type RemoveRegistrySourceData struct {
	Registry RegistrySummary `json:"registry"`
}

// EditRegistrySourceData is the success `data` payload for edit-source
// (MCP-1072, PUT /api/v1/registries/{id}). It echoes the updated registry.
type EditRegistrySourceData struct {
	Registry RegistrySummary `json:"registry"`
}

// SuccessResponse is the standard success response wrapper for API endpoints.
type SuccessResponse struct {
	Success bool        `json:"success"`
	Data    interface{} `json:"data" swaggertype:"object"`
}

// ErrorResponse is the standard error response for API endpoints.
// All error responses include a request_id for log correlation.
type ErrorResponse struct {
	Success   bool   `json:"success"`
	Error     string `json:"error"`
	RequestID string `json:"request_id,omitempty"`
}

// HealthStatus represents the unified health status of an upstream MCP server.
// Calculated once in the backend and rendered identically by all interfaces.
type HealthStatus struct {
	// Level indicates the health level: "healthy", "degraded", or "unhealthy"
	Level string `json:"level"`

	// AdminState indicates the admin state: "enabled", "disabled", or "quarantined"
	AdminState string `json:"admin_state"`

	// Summary is a human-readable status message (e.g., "Connected (5 tools)")
	Summary string `json:"summary"`

	// Detail is an optional longer explanation of the status
	Detail string `json:"detail,omitempty"`

	// Action is the suggested fix action: "login", "restart", "enable", "approve", "view_logs", "set_secret", "configure", or "" (none)
	Action string `json:"action,omitempty"`
}

// UpdateInfo represents version update check information
type UpdateInfo struct {
	Available     bool       `json:"available"`                // Whether an update is available
	LatestVersion string     `json:"latest_version,omitempty"` // Latest version available (e.g., "v1.2.3")
	ReleaseURL    string     `json:"release_url,omitempty"`    // URL to the release page
	CheckedAt     *time.Time `json:"checked_at,omitempty"`     // When the update check was performed
	IsPrerelease  bool       `json:"is_prerelease,omitempty"`  // Whether the latest version is a prerelease
	CheckError    string     `json:"check_error,omitempty"`    // Error message if update check failed
}

// InfoEndpoints represents the available API endpoints
type InfoEndpoints struct {
	HTTP   string `json:"http"`   // HTTP endpoint address (e.g., "127.0.0.1:8080")
	Socket string `json:"socket"` // Unix socket path (empty if disabled)
}

// InfoResponse is the response for GET /api/v1/info
type InfoResponse struct {
	Version    string        `json:"version"`          // Current MCPProxy version
	WebUIURL   string        `json:"web_ui_url"`       // URL to access the web control panel
	ListenAddr string        `json:"listen_addr"`      // Listen address (e.g., "127.0.0.1:8080")
	Endpoints  InfoEndpoints `json:"endpoints"`        // Available API endpoints
	Update     *UpdateInfo   `json:"update,omitempty"` // Update information (if available)
}
