//! Per-tenant API tokens used by `compliance-mcp` to authenticate MCP
//! HTTP requests on behalf of LLM clients (Claude Desktop, Cursor,
//! ChatGPT, etc.) that can't run a Keycloak OIDC flow.
//!
//! Tokens are opaque strings of the form `mcpt_<44 url-safe random
//! chars>`. The raw value is shown to the user exactly once at
//! creation; the database only ever sees the SHA-256 hash. Lookups go
//! through the cross-tenant `<prefix>__admin.mcp_tokens` collection
//! and return the `tenant_id` the MCP server should route to.

use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};

/// Persisted token metadata. `token_hash` is the SHA-256 hex of the
/// raw token; the raw token itself is never stored.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct McpToken {
    #[serde(rename = "_id", skip_serializing_if = "Option::is_none")]
    pub id: Option<bson::oid::ObjectId>,
    /// SHA-256 hex of the raw token. Unique index in the collection.
    pub token_hash: String,
    /// First 8 chars of the raw token — purely for UI display so users
    /// can identify which token is which without re-issuing.
    pub token_prefix: String,
    /// Routes to `<db_prefix>_<tenant_id>` on MCP requests.
    pub tenant_id: String,
    /// User-given label, e.g. "Claude Desktop" or "Sharang's laptop".
    pub name: String,
    /// Keycloak `sub` of the user who created this token, for audit.
    pub created_by: String,
    #[serde(with = "super::serde_helpers::bson_datetime")]
    pub created_at: DateTime<Utc>,
    #[serde(default, with = "super::serde_helpers::opt_bson_datetime")]
    pub last_used_at: Option<DateTime<Utc>>,
    /// Soft-delete flag. A revoked token doc stays around for audit
    /// but never authenticates.
    #[serde(default)]
    pub revoked: bool,
}

/// Public projection of a token — never includes the hash.
/// Returned by `GET /api/v1/mcp-tokens`.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct McpTokenView {
    pub id: String,
    pub name: String,
    /// `mcpt_xxxx…` so the user can identify which row is which.
    pub token_prefix: String,
    pub created_by: String,
    #[serde(with = "super::serde_helpers::bson_datetime")]
    pub created_at: DateTime<Utc>,
    #[serde(default, with = "super::serde_helpers::opt_bson_datetime")]
    pub last_used_at: Option<DateTime<Utc>>,
    pub revoked: bool,
}

impl From<&McpToken> for McpTokenView {
    fn from(t: &McpToken) -> Self {
        Self {
            id: t.id.map(|o| o.to_hex()).unwrap_or_default(),
            name: t.name.clone(),
            token_prefix: t.token_prefix.clone(),
            created_by: t.created_by.clone(),
            created_at: t.created_at,
            last_used_at: t.last_used_at,
            revoked: t.revoked,
        }
    }
}
