use avam_protocol::Packets;
use tokio::sync::mpsc::Sender;

use crate::{
    domain::api::models::oauth::*,
    inbound::http::handlers::oauth::{AuthorizationCodeRequest, VerifyClientAuthorizationRequest},
};

use super::super::models::user::*;
use std::future::Future;

pub trait ApiService: Clone + Send + Sync + 'static {
    // -- -
    // Websocket
    // ---
    fn add_connection(&self, user: &User, sender: Sender<Packets>);

    fn has_connection(&self, user: &User) -> bool;

    fn remove_connection(&self, user: &User);

    fn send(
        &self,
        user: &User,
        packet: Packets,
    ) -> impl Future<Output = Result<(), anyhow::Error>> + Send;

    // ---
    // USER
    // ---
    fn create_user(
        &self,
        req: CreateUserRequest,
    ) -> impl Future<Output = Result<User, CreateUserError>> + Send;

    fn get_user_session(
        &self,
        session: &axum_session::SessionAnySession, // TODO: Get rid of this and make cleaner
    ) -> impl Future<Output = Option<User>> + Send;

    fn activate_user_account(
        &self,
        token: ActivationToken,
    ) -> impl Future<Output = Result<User, ActivateUserError>> + Send;

    fn user_login(
        &self,
        req: UserLoginRequest,
    ) -> impl Future<Output = Result<User, UserLoginError>> + Send;

    fn forgot_password(&self, email: &EmailAddress) -> impl Future<Output = ()> + Send;

    fn reset_password(
        &self,
        token: &PasswordResetToken,
        password: &Password,
    ) -> impl Future<Output = Result<User, ResetPasswordError>> + Send;

    fn find_user_by_password_reset_token(
        &self,
        token: &PasswordResetToken,
    ) -> impl Future<Output = Option<User>> + Send;

    // ---
    // OAUTH
    // ---
    fn find_client_by_id(&self, id: uuid::Uuid) -> impl Future<Output = Option<Client>> + Send;

    fn generate_authorization_code(
        &self,
        user: &User,
        req: AuthorizeRequest,
    ) -> impl Future<Output = Result<AuthorizationResponse, anyhow::Error>> + Send;

    fn create_token(
        &self,
        req: AuthorizationCodeRequest,
    ) -> impl Future<Output = Result<TokenSubject, TokenError>> + Send;

    /// ---
    /// WS
    /// ---
    fn verify_client_authorization(
        &self,
        req: VerifyClientAuthorizationRequest,
    ) -> impl Future<Output = Result<User, anyhow::Error>> + Send;
}
