mod testprotocol;
mod testsupport;

use crate::testprotocol::acme::user::v1::{AccessToken, Bucket};
use crate::testsupport::get_session_store;
use pbbson::Model;
use pbjson_types::{Duration, Timestamp};
use saas_rs_sdk::storage::Error;

#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
async fn can_create_access_token_and_auto_assign_id() {
    let session_store = get_session_store!();
    let access_token = AccessToken {
        ..Default::default()
    };
    let access_token: AccessToken = session_store
        .create(Bucket::AccessTokens, Model::try_from(&access_token).unwrap(), None)
        .await
        .expect("Expected to be able to create access token")
        .try_into()
        .unwrap();
    assert!(!access_token.id.is_empty());
}

#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
async fn can_create_access_token_with_caller_assigned_xid() {
    let session_store = get_session_store!();
    let id = xid::new().to_string();
    let access_token = AccessToken {
        id: id.clone(),
        ..Default::default()
    };
    let access_token: AccessToken = session_store
        .create(Bucket::AccessTokens, Model::try_from(&access_token).unwrap(), None)
        .await
        .expect("Expected to be able to create access token")
        .try_into()
        .unwrap();
    assert_eq!(access_token.id, id);
}

#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
async fn cannot_find_non_existent_access_token() {
    let session_store = get_session_store!();
    let id = xid::new().to_string();
    let res = session_store.find(Bucket::AccessTokens, &id).await;
    assert!(res.is_err());
    assert!(matches!(res.err().unwrap(), Error::NotFound { .. }));
}

#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
async fn cannot_find_non_existent_refresh_token() {
    let session_store = get_session_store!();
    let id = xid::new().to_string();
    let res = session_store.find(Bucket::RefreshTokens, &id).await;
    assert!(res.is_err());
    assert!(matches!(res.err().unwrap(), Error::NotFound { .. }));
}

#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
async fn can_perform_crud_operations() {
    let session_store = get_session_store!();

    // Create access token
    let access_token = AccessToken {
        id: xid::new().to_string(),
        expires_at: Some(Timestamp { seconds: 1749046039, nanos: 0 }),
        expires_in: Some(Duration {
            seconds: 123,
            nanos: 234,
        }),
        ..Default::default()
    };
    let access_token: AccessToken = session_store
        .create(Bucket::AccessTokens, Model::try_from(&access_token).unwrap(), None)
        .await
        .expect("Expected to be able to create access token")
        .try_into()
        .unwrap();

    let refresh_token = xid::new().to_string();
    let mut refresh_token_model = Model::default();
    refresh_token_model.insert("id", &refresh_token);
    session_store
        .create(Bucket::RefreshTokens, refresh_token_model, None)
        .await
        .expect("Expected to be able to create refresh token");

    // Find One access token
    let access_token_reloaded: AccessToken = session_store
        .find(Bucket::AccessTokens, &access_token.id)
        .await
        .expect("Expected to be able to find newly created access token")
        .try_into()
        .unwrap();
    assert_eq!(access_token, access_token_reloaded);

    // Find One refresh token
    let maybe = session_store.find(Bucket::RefreshTokens, &refresh_token).await;
    assert!(maybe.is_ok(), "Expected to be able to find newly created refresh token");
}
