use axum::{
    Json,
    extract::{FromRequest, Request},
    http::StatusCode,
};
use serde::Deserialize;

#[derive(Deserialize, Debug)]
pub struct CreateConversationValues {
    pub name: String,
}

pub struct CreateConversationPayload(pub CreateConversationValues);

impl<S> FromRequest<S> for CreateConversationPayload
where
    S: Send + Sync,
{
    type Rejection = (StatusCode, String);

    async fn from_request(req: Request, state: &S) -> Result<Self, Self::Rejection> {
        let Json(payload) = Json::<CreateConversationValues>::from_request(req, state)
            .await
            .map_err(|err| (StatusCode::BAD_REQUEST, format!("Invalid body: {}", err)))?;

        Ok(CreateConversationPayload(payload))
    }
}

#[derive(Deserialize, Debug)]
pub struct AddUserConversationValues {
    pub conv_id: u32,
    pub users: Vec<u32>,
}

pub struct AddUserConversationPayload(pub AddUserConversationValues);

impl<S> FromRequest<S> for AddUserConversationPayload
where
    S: Send + Sync,
{
    type Rejection = (StatusCode, String);

    async fn from_request(req: Request, state: &S) -> Result<Self, Self::Rejection> {
        let Json(payload) = Json::<AddUserConversationValues>::from_request(req, state)
            .await
            .map_err(|err| (StatusCode::BAD_REQUEST, format!("Invalid body: {}", err)))?;

        Ok(AddUserConversationPayload(payload))
    }
}

#[derive(Deserialize, Debug)]
pub struct SendMessageValues {
    pub conv_id: u32,
    pub message: String,
}

pub struct SendMessagePayload(pub SendMessageValues);

impl<S> FromRequest<S> for SendMessagePayload
where
    S: Send + Sync,
{
    type Rejection = (StatusCode, String);

    async fn from_request(req: Request, state: &S) -> Result<Self, Self::Rejection> {
        let Json(payload) = Json::<SendMessageValues>::from_request(req, state)
            .await
            .map_err(|err| (StatusCode::BAD_REQUEST, format!("Invalid body: {}", err)))?;

        Ok(SendMessagePayload(payload))
    }
}

#[derive(Deserialize, Debug)]
pub struct GetMessagesValues {
    pub conv_id: u32,
    pub timestamp: Option<String>,
}

pub struct GetMessagesPayload(pub GetMessagesValues);

impl<S> FromRequest<S> for GetMessagesPayload
where
    S: Send + Sync,
{
    type Rejection = (StatusCode, String);

    async fn from_request(req: Request, state: &S) -> Result<Self, Self::Rejection> {
        let Json(payload) = Json::<GetMessagesValues>::from_request(req, state)
            .await
            .map_err(|err| (StatusCode::BAD_REQUEST, format!("Invalid body: {}", err)))?;

        Ok(GetMessagesPayload(payload))
    }
}
