use actix_web::{HttpRequest, HttpResponse, web};
use channel::{ChannelBus, ChannelTokenApply, TOKEN_TTL_SECS};
use serde::Deserialize;
use session::SessionExt;

use crate::error::ApiError;

use super::rest::channel_err;

#[derive(Debug, Deserialize, utoipa::ToSchema)]
pub struct TokenRequest {
    pub device_id: String,
    pub client_id: String,
}

#[derive(Debug, serde::Serialize, utoipa::ToSchema)]
pub struct TokenResponse {
    pub access_token: String,
    pub expires_in_secs: u64,
}

#[utoipa::path(
    post,
    path = "/api/v1/ws/token",
    request_body = TokenRequest,
    responses((status = 200, body = TokenResponse)),
    tag = "channel"
)]
pub async fn generate_token(
    req: HttpRequest,
    body: web::Json<TokenRequest>,
    bus: web::Data<ChannelBus>,
) -> Result<HttpResponse, ApiError> {
    let user_id = req
        .get_session()
        .user()
        .ok_or_else(|| ApiError(service::error::AppError::Unauthorized))?;

    let apply = ChannelTokenApply {
        device_id: body.device_id.clone(),
        client_id: body.client_id.clone(),
    };

    let token = bus
        .apply_access_token(user_id, apply)
        .await
        .map_err(channel_err)?;

    Ok(HttpResponse::Ok().json(TokenResponse {
        access_token: token.access_token,
        expires_in_secs: TOKEN_TTL_SECS,
    }))
}
