//! Request and response model types for the SentryAgent.ai AgentIdP API.
//!
//! All types implement `serde::Serialize` and `serde::Deserialize` for
//! transparent JSON encoding. `Option` fields are omitted from serialized
//! output when `None`.

use serde::{Deserialize, Serialize};

// ─── Request types ────────────────────────────────────────────────────────────

/// Request body for `POST /agents` — register a new agent identity.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RegisterAgentRequest {
    /// Human-readable name for the agent.
    pub name: String,
    /// Optional description of the agent's purpose.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
    /// Functional category of the agent (e.g. `"worker"`, `"orchestrator"`).
    pub agent_type: String,
    /// List of capability strings the agent exposes (e.g. `"read:files"`).
    pub capabilities: Vec<String>,
    /// Arbitrary metadata to attach to the agent record.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub metadata: Option<serde_json::Value>,
}

/// Request body for `PATCH /agents/{id}` — partially update an existing agent.
///
/// Only fields that are `Some` are sent to the API; `None` fields are omitted.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UpdateAgentRequest {
    /// New human-readable name.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub name: Option<String>,
    /// New description.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
    /// Replacement capability list.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub capabilities: Option<Vec<String>>,
    /// Whether to list the agent in the public marketplace.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub is_public: Option<bool>,
    /// Replacement metadata object.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub metadata: Option<serde_json::Value>,
}

/// Query parameters for `GET /audit-logs`.
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct AuditLogFilters {
    /// Filter by agent ID.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub agent_id: Option<String>,
    /// Filter by event type string.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub event_type: Option<String>,
    /// Start of time range (ISO 8601).
    #[serde(skip_serializing_if = "Option::is_none")]
    pub from: Option<String>,
    /// End of time range (ISO 8601).
    #[serde(skip_serializing_if = "Option::is_none")]
    pub to: Option<String>,
    /// Page number (1-based).
    pub page: u32,
    /// Number of results per page.
    pub per_page: u32,
}

/// Query parameters for `GET /marketplace/agents`.
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct MarketplaceFilters {
    /// Free-text search query.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub q: Option<String>,
    /// Filter by capability string.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub capability: Option<String>,
    /// Filter by publisher identifier.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub publisher: Option<String>,
    /// Page number (1-based).
    pub page: u32,
    /// Number of results per page.
    pub per_page: u32,
}

/// Request body for `POST /delegation` — create an A2A delegation token.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DelegateRequest {
    /// The agent ID that receives delegated authority.
    pub delegatee_agent_id: String,
    /// Scopes being delegated.
    pub scopes: Vec<String>,
    /// Token lifetime in seconds.
    pub ttl_seconds: u64,
}

// ─── Response types ───────────────────────────────────────────────────────────

/// A registered AI agent identity returned by the API.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Agent {
    /// Unique agent identifier (UUID).
    pub id: String,
    /// Human-readable name.
    pub name: String,
    /// Optional description.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
    /// Capabilities the agent exposes.
    pub capabilities: Vec<String>,
    /// Decentralised Identifier for the agent.
    pub did: String,
    /// Whether the agent is listed in the public marketplace.
    pub is_public: bool,
    /// ISO 8601 creation timestamp.
    pub created_at: String,
    /// ISO 8601 last-updated timestamp.
    pub updated_at: String,
}

/// Paginated list of agents returned by `GET /agents`.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AgentList {
    /// Agents on the current page.
    pub agents: Vec<Agent>,
    /// Total number of agents matching the query.
    pub total: u64,
    /// Current page number (1-based).
    pub page: u32,
    /// Number of results per page.
    pub per_page: u32,
}

/// OAuth 2.0 access token response (RFC 6749 §4.4.3).
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TokenResponse {
    /// The bearer access token.
    pub access_token: String,
    /// Token type — always `"Bearer"`.
    pub token_type: String,
    /// Seconds until the token expires.
    pub expires_in: u64,
    /// Space-separated list of granted scopes.
    pub scope: String,
}

/// Agent credentials — client ID and (on creation/rotation only) client secret.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Credentials {
    /// OAuth 2.0 client ID.
    pub client_id: String,
    /// OAuth 2.0 client secret (only present on generate/rotate responses).
    pub client_secret: String,
    /// ISO 8601 creation timestamp.
    pub created_at: String,
}

/// A single audit log entry.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AuditLogEntry {
    /// Unique event identifier.
    pub id: String,
    /// Agent ID this event relates to.
    pub agent_id: String,
    /// Type of event that occurred.
    pub event_type: String,
    /// Identity of the actor that triggered the event.
    pub actor: String,
    /// Structured metadata associated with the event.
    pub metadata: serde_json::Value,
    /// ISO 8601 timestamp of the event.
    pub timestamp: String,
}

/// Paginated list of audit log entries.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AuditLogList {
    /// Entries on the current page.
    pub entries: Vec<AuditLogEntry>,
    /// Total number of entries matching the query.
    pub total: u64,
    /// Current page number (1-based).
    pub page: u32,
    /// Number of results per page.
    pub per_page: u32,
}

/// A publicly listed marketplace agent.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MarketplaceAgent {
    /// Unique agent identifier (UUID).
    pub id: String,
    /// Human-readable name.
    pub name: String,
    /// Optional description.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
    /// Capabilities the agent exposes.
    pub capabilities: Vec<String>,
    /// Full W3C DID Document for the agent.
    pub did_document: serde_json::Value,
    /// Publisher identifier or organisation name.
    pub publisher: String,
    /// ISO 8601 creation timestamp.
    pub created_at: String,
}

/// Paginated list of marketplace agents.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MarketplaceAgentList {
    /// Agents on the current page.
    pub agents: Vec<MarketplaceAgent>,
    /// Total number of agents matching the query.
    pub total: u64,
    /// Current page number (1-based).
    pub page: u32,
    /// Number of results per page.
    pub per_page: u32,
}

/// A delegation token granting a delegatee agent authority on behalf of the delegator.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DelegationToken {
    /// Opaque signed delegation token — pass in `X-Delegation-Token` header.
    pub delegation_token: String,
    /// Unique identifier for this delegation chain.
    pub chain_id: String,
    /// Agent ID of the delegator (authority source).
    pub delegator_agent_id: String,
    /// Agent ID of the delegatee (authority recipient).
    pub delegatee_agent_id: String,
    /// Scopes that have been delegated.
    pub scopes: Vec<String>,
    /// ISO 8601 timestamp when the delegation expires.
    pub expires_at: String,
}

/// Result of verifying a delegation token.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DelegationVerification {
    /// Whether the delegation token is valid and unexpired.
    pub valid: bool,
    /// Delegation chain ID, present when `valid` is `true`.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub chain_id: Option<String>,
    /// Delegator agent ID, present when `valid` is `true`.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub delegator_agent_id: Option<String>,
    /// Delegatee agent ID, present when `valid` is `true`.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub delegatee_agent_id: Option<String>,
    /// Delegated scopes, present when `valid` is `true`.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub scopes: Option<Vec<String>>,
    /// Expiry timestamp, present when `valid` is `true`.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub expires_at: Option<String>,
}
