//! Domain types for the ZeroID API.

use serde::{Deserialize, Serialize};
use std::collections::HashMap;

// ── Identity ─────────────────────────────────────────────────────────────────

/// Identity registered in ZeroID — agents, applications, MCP servers, or services.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Identity {
    pub id: String,
    pub account_id: String,
    pub project_id: String,
    pub external_id: String,
    pub name: String,
    pub wimse_uri: String,
    pub identity_type: String,
    #[serde(default, skip_serializing_if = "String::is_empty")]
    pub sub_type: String,
    pub trust_level: String,
    pub status: String,
    pub owner_user_id: String,
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub allowed_scopes: Vec<String>,
    #[serde(default, skip_serializing_if = "String::is_empty")]
    pub public_key_pem: String,
    #[serde(default, skip_serializing_if = "String::is_empty")]
    pub framework: String,
    #[serde(default, skip_serializing_if = "String::is_empty")]
    pub version: String,
    #[serde(default, skip_serializing_if = "String::is_empty")]
    pub publisher: String,
    #[serde(default, skip_serializing_if = "String::is_empty")]
    pub description: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub capabilities: Option<serde_json::Value>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub labels: Option<serde_json::Value>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub metadata: Option<serde_json::Value>,
    #[serde(default, skip_serializing_if = "String::is_empty")]
    pub created_by: String,
    pub created_at: String,
    pub updated_at: String,
}

/// Request body for `POST /api/v1/identities`.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CreateIdentityRequest {
    pub external_id: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub name: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub trust_level: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub identity_type: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub sub_type: Option<String>,
    pub owner_user_id: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub allowed_scopes: Option<Vec<String>>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub public_key_pem: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub framework: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub version: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub publisher: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub capabilities: Option<serde_json::Value>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub labels: Option<serde_json::Value>,
}

/// Request body for `PATCH /api/v1/identities/{id}`.
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct UpdateIdentityRequest {
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub name: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub trust_level: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub identity_type: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub sub_type: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub owner_user_id: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub allowed_scopes: Option<Vec<String>>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub public_key_pem: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub framework: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub version: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub publisher: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub capabilities: Option<serde_json::Value>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub labels: Option<serde_json::Value>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub status: Option<String>,
}

/// List response for identities.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IdentityList {
    pub identities: Vec<Identity>,
    pub total: usize,
}

// ── Agent ────────────────────────────────────────────────────────────────────

/// Agent identity response from the registry.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AgentResponse {
    pub id: String,
    pub account_id: String,
    pub project_id: String,
    pub name: String,
    pub external_id: String,
    pub wimse_uri: String,
    #[serde(default)]
    pub api_key_prefix: String,
    pub identity_type: String,
    #[serde(default)]
    pub sub_type: String,
    pub trust_level: String,
    pub status: String,
    #[serde(default)]
    pub framework: String,
    #[serde(default)]
    pub version: String,
    #[serde(default)]
    pub publisher: String,
    #[serde(default)]
    pub description: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub capabilities: Option<serde_json::Value>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub labels: Option<serde_json::Value>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub metadata: Option<serde_json::Value>,
    pub created_at: String,
    #[serde(default)]
    pub created_by: String,
    pub updated_at: String,
}

/// Response from `POST /api/v1/agents/register` — includes the plaintext API key.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AgentRegistered {
    /// The registered agent. JSON field name is `identity` (matches server response).
    #[serde(rename = "identity")]
    pub agent: AgentResponse,
    pub api_key: String,
}

/// Request body for `POST /api/v1/agents/register`.
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct RegisterAgentRequest {
    pub name: String,
    pub external_id: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub identity_type: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub sub_type: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub trust_level: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub framework: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub version: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub publisher: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub capabilities: Option<serde_json::Value>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub labels: Option<serde_json::Value>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub metadata: Option<serde_json::Value>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub created_by: Option<String>,
}

/// Request body for `PATCH /api/v1/agents/registry/{id}`.
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct UpdateAgentRequest {
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub name: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub sub_type: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub trust_level: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub framework: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub version: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub publisher: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub capabilities: Option<serde_json::Value>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub labels: Option<serde_json::Value>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub metadata: Option<serde_json::Value>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub status: Option<String>,
}

/// Paginated list of agents.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AgentList {
    pub agents: Vec<AgentResponse>,
    pub total: usize,
    pub limit: usize,
    pub offset: usize,
}

// ── OAuth Client ─────────────────────────────────────────────────────────────

/// Registered OAuth2 client.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OAuthClient {
    pub id: String,
    pub account_id: String,
    pub project_id: String,
    pub client_id: String,
    pub name: String,
    #[serde(default)]
    pub identity_id: String,
    #[serde(default)]
    pub grant_types: Vec<String>,
    #[serde(default)]
    pub redirect_uris: Vec<String>,
    #[serde(default)]
    pub scopes: Vec<String>,
    pub is_active: bool,
    pub created_at: String,
    pub updated_at: String,
}

/// Request body for `POST /api/v1/oauth/clients`.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CreateOAuthClientRequest {
    pub name: String,
    pub external_id: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub grant_types: Option<Vec<String>>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub scopes: Option<Vec<String>>,
}

/// Response from creating or rotating an OAuth client — includes the plaintext secret.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OAuthClientCreated {
    pub client: OAuthClient,
    pub client_secret: String,
    pub note: String,
}

/// List response for OAuth clients.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OAuthClientList {
    pub clients: Vec<OAuthClient>,
    pub total: usize,
}

/// Delete confirmation for OAuth clients.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OAuthClientDeleted {
    pub deleted: bool,
    pub id: String,
}

// ── Credential Policy ────────────────────────────────────────────────────────

/// Credential policy governing token issuance constraints.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CredentialPolicy {
    pub id: String,
    pub account_id: String,
    pub project_id: String,
    pub name: String,
    #[serde(default)]
    pub description: String,
    pub max_ttl_seconds: i64,
    #[serde(default)]
    pub allowed_grant_types: Vec<String>,
    #[serde(default)]
    pub allowed_scopes: Vec<String>,
    #[serde(default)]
    pub required_trust_level: String,
    #[serde(default)]
    pub required_attestation: String,
    pub max_delegation_depth: i64,
    pub is_active: bool,
    pub created_at: String,
    pub updated_at: String,
}

/// Request body for `POST /api/v1/credential-policies`.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CreateCredentialPolicyRequest {
    pub name: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub max_ttl_seconds: Option<i64>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub allowed_grant_types: Option<Vec<String>>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub allowed_scopes: Option<Vec<String>>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub required_trust_level: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub required_attestation: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub max_delegation_depth: Option<i64>,
}

/// Request body for `PATCH /api/v1/credential-policies/{id}`.
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct UpdateCredentialPolicyRequest {
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub name: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub max_ttl_seconds: Option<i64>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub allowed_grant_types: Option<Vec<String>>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub allowed_scopes: Option<Vec<String>>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub required_trust_level: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub required_attestation: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub max_delegation_depth: Option<i64>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub is_active: Option<bool>,
}

/// List response for credential policies.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CredentialPolicyList {
    pub credential_policies: Vec<CredentialPolicy>,
    pub total: usize,
}

// ── API Key ──────────────────────────────────────────────────────────────────

/// API key metadata (hash is never exposed).
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ApiKey {
    pub id: String,
    pub name: String,
    #[serde(default)]
    pub description: String,
    pub key_prefix: String,
    pub key_version: i64,
    pub account_id: String,
    pub project_id: String,
    pub identity_id: String,
    #[serde(default)]
    pub created_by: String,
    #[serde(default)]
    pub scopes: Vec<String>,
    #[serde(default)]
    pub environment: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub expires_at: Option<String>,
    pub state: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub revoked_at: Option<String>,
    #[serde(default)]
    pub revoked_by: String,
    #[serde(default)]
    pub revoke_reason: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub last_used_at: Option<String>,
    #[serde(default)]
    pub last_used_ip: String,
    pub usage_count: i64,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub metadata: Option<serde_json::Value>,
    #[serde(default)]
    pub ip_allowlist: Vec<String>,
    pub credential_policy_id: String,
    #[serde(default)]
    pub rate_limit_rps: i64,
    #[serde(default)]
    pub replaced_by: String,
    pub created_at: String,
    pub updated_at: String,
}

/// Request body for `POST /api/v1/api-keys`.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CreateApiKeyRequest {
    pub name: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub identity_id: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub scopes: Option<Vec<String>>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub environment: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub expires_in_days: Option<i64>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub metadata: Option<serde_json::Value>,
}

/// Response from `POST /api/v1/api-keys` — includes the full key (shown once).
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ApiKeyCreated {
    pub id: String,
    pub name: String,
    #[serde(default)]
    pub description: String,
    pub key: String,
    pub key_prefix: String,
    #[serde(default)]
    pub environment: String,
    #[serde(default)]
    pub scopes: Vec<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub expires_at: Option<String>,
    pub created_at: String,
}

/// Paginated list of API keys.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ApiKeyList {
    pub keys: Vec<ApiKey>,
    pub total: usize,
    pub page: usize,
    pub limit: usize,
}

/// Request body for `POST /api/v1/api-keys/{id}/revoke`.
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct RevokeApiKeyRequest {
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub reason: Option<String>,
}

/// Response from revoking an API key.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ApiKeyRevoked {
    pub message: String,
}

// ── OAuth Token ──────────────────────────────────────────────────────────────

/// Request body for `POST /oauth2/token`.
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct TokenRequest {
    pub grant_type: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub client_id: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub client_secret: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub scope: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub subject: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub api_key: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub subject_token: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub actor_token: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub code: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub code_verifier: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub redirect_uri: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub refresh_token: Option<String>,
}

/// RFC 6749 token response.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AccessToken {
    pub access_token: String,
    pub token_type: String,
    pub expires_in: i64,
    #[serde(default)]
    pub scope: String,
    pub jti: String,
    pub iat: i64,
    #[serde(default)]
    pub account_id: String,
    #[serde(default)]
    pub project_id: String,
    #[serde(default)]
    pub external_id: String,
    #[serde(default)]
    pub user_id: String,
    #[serde(default, skip_serializing_if = "String::is_empty")]
    pub refresh_token: String,
}

/// RFC 7662 token introspection response.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TokenIntrospection {
    pub active: bool,
    #[serde(default)]
    pub iss: String,
    #[serde(default)]
    pub sub: String,
    #[serde(default)]
    pub exp: i64,
    #[serde(default)]
    pub iat: i64,
    #[serde(default)]
    pub jti: String,
    #[serde(default)]
    pub scope: String,
    #[serde(default)]
    pub account_id: String,
    #[serde(default)]
    pub project_id: String,
    #[serde(default)]
    pub trust_level: String,
    #[serde(default)]
    pub delegation_depth: i32,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub act: Option<ActClaim>,
    #[serde(default)]
    pub owner_user_id: String,
    /// Additional claims not covered by typed fields.
    #[serde(flatten)]
    pub claims: HashMap<String, serde_json::Value>,
}

/// RFC 8693 "act" claim — the entity the principal is acting on behalf of.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ActClaim {
    pub sub: String,
}

/// Request body for `POST /oauth2/token/introspect`.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IntrospectRequest {
    pub token: String,
}

/// Request body for `POST /oauth2/token/revoke`.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RevokeTokenRequest {
    pub token: String,
}

/// Response from `POST /oauth2/token/revoke`.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TokenRevoked {
    pub revoked: bool,
}

// ── CAE Signal ───────────────────────────────────────────────────────────────

/// Continuous Access Evaluation signal.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CAESignal {
    pub id: String,
    pub account_id: String,
    pub project_id: String,
    pub identity_id: String,
    pub signal_type: String,
    pub severity: String,
    pub source: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub payload: Option<HashMap<String, serde_json::Value>>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub processed_at: Option<String>,
    pub created_at: String,
}

/// Request body for `POST /api/v1/signals/ingest`.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IngestSignalRequest {
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub identity_id: Option<String>,
    pub signal_type: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub severity: Option<String>,
    pub source: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub payload: Option<HashMap<String, serde_json::Value>>,
}

/// List response for signals.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SignalList {
    pub signals: Vec<CAESignal>,
    pub total: usize,
}

// ── JWKS ─────────────────────────────────────────────────────────────────────

/// JSON Web Key Set response from `GET /.well-known/jwks.json`.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct JwksResponse {
    pub keys: Vec<serde_json::Value>,
}

// ── Health ───────────────────────────────────────────────────────────────────

/// Health check response from `GET /health`.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HealthResponse {
    pub status: String,
    #[serde(flatten)]
    pub extra: HashMap<String, serde_json::Value>,
}
