use chrono::{Duration, TimeZone, Utc};
use delegated::{DelegationTokenBuilder, validate_token};
use ed25519_dalek::SigningKey;
use proptest::prelude::*;

fn now() -> chrono::DateTime<Utc> {
    Utc.with_ymd_and_hms(2026, 7, 1, 12, 0, 0).single().unwrap()
}

proptest! {
    #[test]
    fn builder_produces_contract_valid_tokens(
        token_suffix in "[a-z0-9-]{1,32}",
        nonce_suffix in "[a-z0-9-]{1,32}",
    ) {
        let key = SigningKey::from_bytes(&[7; 32]);
        let issued = now() - Duration::minutes(1);
        let expires = now() + Duration::minutes(10);
        let nonce = format!("nonce-{nonce_suffix:0>16}");
        prop_assume!(nonce.len() >= 16);

        let token = DelegationTokenBuilder::new()
            .token_id(format!("token-{token_suffix}"))
            .issuer("https://issuer.example")
            .agent_id("agent:scheduler")
            .delegator_id("user:alice")
            .audience("calendar-api")
            .allowed_action("calendar.create")
            .allowed_resource("calendar:alice")
            .max_delegation_depth(0)
            .issued_at(issued)
            .expires_at(expires)
            .nonce(nonce)
            .key_id("issuer-1")
            .build_and_sign(&key)
            .expect("builder should succeed for valid inputs");

        validate_token(&token).expect("signed token should satisfy contract validation");
        prop_assert!(!token.signature.is_empty());
    }

    #[test]
    fn builder_rejects_missing_required_fields(field in 0u8..8) {
        let key = SigningKey::from_bytes(&[7; 32]);
        let issued = now() - Duration::minutes(1);
        let expires = now() + Duration::minutes(10);

        let builder = match field {
            0 => DelegationTokenBuilder::new()
                .issuer("https://issuer.example")
                .agent_id("agent:scheduler")
                .delegator_id("user:alice")
                .audience("calendar-api")
                .allowed_action("calendar.create")
                .issued_at(issued)
                .expires_at(expires)
                .nonce("nonce-000000000001")
                .key_id("issuer-1"),
            1 => DelegationTokenBuilder::new()
                .token_id("token-1")
                .agent_id("agent:scheduler")
                .delegator_id("user:alice")
                .audience("calendar-api")
                .allowed_action("calendar.create")
                .issued_at(issued)
                .expires_at(expires)
                .nonce("nonce-000000000001")
                .key_id("issuer-1"),
            2 => DelegationTokenBuilder::new()
                .token_id("token-1")
                .issuer("https://issuer.example")
                .delegator_id("user:alice")
                .audience("calendar-api")
                .allowed_action("calendar.create")
                .issued_at(issued)
                .expires_at(expires)
                .nonce("nonce-000000000001")
                .key_id("issuer-1"),
            3 => DelegationTokenBuilder::new()
                .token_id("token-1")
                .issuer("https://issuer.example")
                .agent_id("agent:scheduler")
                .audience("calendar-api")
                .allowed_action("calendar.create")
                .issued_at(issued)
                .expires_at(expires)
                .nonce("nonce-000000000001")
                .key_id("issuer-1"),
            4 => DelegationTokenBuilder::new()
                .token_id("token-1")
                .issuer("https://issuer.example")
                .agent_id("agent:scheduler")
                .delegator_id("user:alice")
                .allowed_action("calendar.create")
                .issued_at(issued)
                .expires_at(expires)
                .nonce("nonce-000000000001")
                .key_id("issuer-1"),
            5 => DelegationTokenBuilder::new()
                .token_id("token-1")
                .issuer("https://issuer.example")
                .agent_id("agent:scheduler")
                .delegator_id("user:alice")
                .audience("calendar-api")
                .issued_at(issued)
                .expires_at(expires)
                .nonce("nonce-000000000001")
                .key_id("issuer-1"),
            6 => DelegationTokenBuilder::new()
                .token_id("token-1")
                .issuer("https://issuer.example")
                .agent_id("agent:scheduler")
                .delegator_id("user:alice")
                .audience("calendar-api")
                .allowed_action("calendar.create")
                .issued_at(issued)
                .expires_at(expires)
                .key_id("issuer-1"),
            _ => DelegationTokenBuilder::new()
                .token_id("token-1")
                .issuer("https://issuer.example")
                .agent_id("agent:scheduler")
                .delegator_id("user:alice")
                .audience("calendar-api")
                .allowed_action("calendar.create")
                .issued_at(issued)
                .expires_at(expires)
                .nonce("nonce-000000000001"),
        };

        prop_assert!(builder.build_and_sign(&key).is_err());
    }
}
