//! `Request` — receiver-initiated identity request (= request-first mode).
//!
//! Spec reference: `draft-vandemeent-iddrop-00` §5.2, §7.3, Appendix A.

use crate::nonce::ChallengeNonce;
use serde::{Deserialize, Serialize};

/// Spec §5.2 + §7.3: receiver-initiated identity request.
///
/// Required fields per the draft: `request_id`, `challenge_nonce`,
/// `requested_claim_type`, `receiver_pubkey`, `requested_aint`,
/// `causal_parent`, `expires_at`.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Request {
    /// Protocol version, always [`crate::PROTOCOL_VERSION`].
    pub protocol: String,

    /// Unique request id — receiver will reject claims that do not echo it.
    pub request_id: String,

    /// Challenge nonce — receiver-issued, must be echoed by sender.
    pub challenge_nonce: ChallengeNonce,

    /// AINS handle being requested (= "give me proof of jasper.aint").
    pub requested_aint: String,

    /// What kind of claim is requested — typically `"identity"`.
    pub requested_claim_type: String,

    /// Receiver's own Ed25519 pubkey (hex). Where the sealed reply lands.
    pub receiver_pubkey: String,

    /// Optional pointer to a prior claim that this request extends.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub causal_parent: Option<String>,

    /// Unix-seconds when this request expires.
    pub expires_at: u64,
}

impl Request {
    /// Build a fresh request for an identity claim.
    pub fn new(
        requested_aint: impl Into<String>,
        requested_claim_type: impl Into<String>,
        receiver_pubkey: impl Into<String>,
        ttl_seconds: u64,
    ) -> Self {
        use rand::RngCore;
        let mut id = [0u8; 16];
        rand::thread_rng().fill_bytes(&mut id);
        let now = crate::claim::current_unix_seconds();
        Self {
            protocol: crate::PROTOCOL_VERSION.to_string(),
            request_id: hex::encode(id),
            challenge_nonce: ChallengeNonce::new(),
            requested_aint: requested_aint.into(),
            requested_claim_type: requested_claim_type.into(),
            receiver_pubkey: receiver_pubkey.into(),
            causal_parent: None,
            expires_at: now + ttl_seconds,
        }
    }
}
