mod capability;
pub use capability::{Capability, DecodingError, EncodingError, VerificationError};
pub use ucan_capabilities_object::{
    AbilityName, AbilityNameRef, AbilityNamespace, AbilityNamespaceRef, AbilityRef, CapsInner,
    ConvertError, NotaBeneCollection,
};
pub const RESOURCE_PREFIX: &str = "urn:recap:";
#[cfg(test)]
mod test {
    use super::*;
    use serde_json::Value;
    use siws::message::SiwsMessage;
    const SIWE_WITH_INTERLEAVED_RES: &str =
        include_str!("../tests/siwe_with_interleaved_resources.txt");
    const SIWE_WITH_STATEMENT_NO_CAPS: &str =
        include_str!("../tests/siwe_with_statement_no_caps.txt");
    const SIWE_WITH_STATEMENT: &str = include_str!("../tests/siwe_with_statement.txt");
    const SIWE_NO_CAPS: &str = include_str!("../tests/siwe_with_no_caps.txt");
    const SIWE: &str = include_str!("../tests/siwe_with_caps.txt");
    #[test]
    fn no_caps_statement_append() {
        let msg = Capability::<Value>::default()
            .build_message(SiwsMessage {
                domain: "example.com".parse().unwrap(),
                address: "0000000000000000000000000000000000000000".into(),
                statement: Some("Some custom statement.".into()),
                uri: Some("did:key:example".parse().unwrap()),
                version: Some("1".into()),
                chain_id: Some("testnet".into()),
                nonce: Some("mynonce1".into()),
                issued_at: Some("2022-06-21T12:00:00.000Z".parse().unwrap()),
                expiration_time: None,
                not_before: None,
                request_id: None,
                resources: vec![],
            })
            .expect("failed to build SIWE delegation");
        assert_eq!(
            SIWE_WITH_STATEMENT_NO_CAPS,
            msg.to_string(),
            "generated SIWE message did not match expectation"
        );
    }
    #[test]
    fn build_delegation_statement_append() {
        let mut cap = Capability::<Value>::default();
        cap.with_action_convert("credential:*", "credential/present", [])
            .unwrap();
        let msg = cap
            .build_message(SiwsMessage {
                domain: "example.com".parse().unwrap(),
                address: "0000000000000000000000000000000000000000".into(),
                statement: Some("Some custom statement.".into()),
                uri: Some("did:key:example".parse().unwrap()),
                version: Some("1".into()),
                chain_id: Some("testnet".into()),
                nonce: Some("mynonce1".into()),
                issued_at: Some("2022-06-21T12:00:00.000Z".parse().unwrap()),
                expiration_time: None,
                not_before: None,
                request_id: None,
                resources: vec!["http://example.com".parse().unwrap()],
            })
            .expect("failed to build SIWE delegation");
        assert_eq!(
            SIWE_WITH_STATEMENT.trim(),
            msg.to_string(),
            "generated SIWE message did not match expectation"
        );
    }
    #[test]
    fn no_caps() {
        let msg = Capability::<Value>::default()
            .build_message(SiwsMessage {
                domain: "example.com".parse().unwrap(),
                address: "0000000000000000000000000000000000000000".into(),
                statement: None,
                uri: Some("did:key:example".parse().unwrap()),
                version: Some("1".into()),
                chain_id: Some("testnet".into()),
                nonce: Some("mynonce1".into()),
                issued_at: Some("2022-06-21T12:00:00.000Z".parse().unwrap()),
                expiration_time: None,
                not_before: None,
                request_id: None,
                resources: vec![],
            })
            .expect("failed to build SIWE delegation");
        assert_eq!(
            SIWE_NO_CAPS,
            msg.to_string(),
            "generated SIWE message did not match expectation"
        );
    }
    #[test]
    fn build_delegation() {
        let msg = Capability::<Value>::default()
            .with_actions_convert("urn:credential:type:type1", [("credential/present", [])])
            .unwrap()
            .with_actions_convert(
                "kepler:ens:example.eth://default/kv",
                [("kv/list", []), ("kv/get", []), ("kv/metadata", [])],
            )
            .unwrap()
            .with_actions_convert(
                "kepler:ens:example.eth://default/kv/public",
                [
                    ("kv/list", []),
                    ("kv/get", []),
                    ("kv/metadata", []),
                    ("kv/put", []),
                    ("kv/delete", []),
                ],
            )
            .unwrap()
            .with_actions_convert(
                "kepler:ens:example.eth://default/kv/dapp-space",
                [
                    ("kv/list", []),
                    ("kv/get", []),
                    ("kv/metadata", []),
                    ("kv/put", []),
                    ("kv/delete", []),
                ],
            )
            .unwrap()
            .build_message(SiwsMessage {
                domain: "example.com".parse().unwrap(),
                address: "0000000000000000000000000000000000000000".into(),
                statement: None,
                uri: Some("did:key:example".parse().unwrap()),
                version: Some("1".into()),
                chain_id: Some("testnet".into()),
                nonce: Some("mynonce1".into()),
                issued_at: Some("2022-06-21T12:00:00.000Z".parse().unwrap()),
                expiration_time: None,
                not_before: None,
                request_id: None,
                resources: vec![],
            })
            .expect("failed to build SIWE delegation");
        assert_eq!(
            SIWE.trim(),
            msg.to_string(),
            "generated SIWE message did not match expectation"
        );
    }
    #[test]
    fn verify() {
        let msg: SiwsMessage = SIWE.trim().parse().unwrap();
        assert!(
            Capability::<Value>::extract_and_verify(&msg)
                .transpose()
                .expect("unable to parse resources as capabilities")
                .is_ok(),
            "statement did not match capabilities"
        );
        let mut altered_msg_1 = msg.clone();
        altered_msg_1
            .statement
            .iter_mut()
            .for_each(|statement| statement.push_str(" I am the walrus!"));
        assert!(
            Capability::<Value>::extract_and_verify(&altered_msg_1).is_err(),
            "altered statement incorrectly matched capabilities"
        );
    }
    #[test]
    fn verify_interleaved_resources() {
        let msg: SiwsMessage = SIWE_WITH_INTERLEAVED_RES.trim().parse().unwrap();
        assert!(
            Capability::<Value>::extract_and_verify(&msg)
                .unwrap()
                .is_none(),
            "recap resource should come last"
        );
    }
}