use axum::{
  extract::{Query, WebSocketUpgrade, ws::Message},
  response::IntoResponse,
};
use futures::SinkExt;
use komodo_client::{
  api::terminal::{
    ConnectDeploymentAttachQuery, ConnectDeploymentExecQuery,
  },
  entities::{
    deployment::Deployment, permission::PermissionLevel,
    server::Server,
  },
};

use crate::{permission::get_check_permissions, resource::get};

#[instrument(name = "ConnectDeploymentExec", skip(ws))]
pub async fn exec(
  Query(ConnectDeploymentExecQuery {
    deployment,
    shell,
    recreate,
  }): Query<ConnectDeploymentExecQuery>,
  ws: WebSocketUpgrade,
) -> impl IntoResponse {
  ws.on_upgrade(async move |socket| {
    let Some((mut client_socket, user)) =
      super::user_ws_login(socket).await
    else {
      return;
    };

    let deployment = match get_check_permissions::<Deployment>(
      &deployment,
      &user,
      PermissionLevel::Read.terminal(),
    )
    .await
    {
      Ok(deployment) => deployment,
      Err(e) => {
        debug!("could not get deployment | {e:#}");
        let _ = client_socket
          .send(Message::text(format!("ERROR: {e:#}")))
          .await;
        let _ = client_socket.close().await;
        return;
      }
    };

    let server =
      match get::<Server>(&deployment.config.server_id).await {
        Ok(server) => server,
        Err(e) => {
          debug!("could not get server | {e:#}");
          let _ = client_socket
            .send(Message::text(format!("ERROR: {e:#}")))
            .await;
          let _ = client_socket.close().await;
          return;
        }
      };

    super::handle_container_exec_terminal(
      client_socket,
      &server,
      deployment.name,
      shell,
      recreate,
    )
    .await
  })
}

#[instrument(name = "ConnectDeploymentAttach", skip(ws))]
pub async fn attach(
  Query(ConnectDeploymentAttachQuery {
    deployment,
    recreate,
  }): Query<ConnectDeploymentAttachQuery>,
  ws: WebSocketUpgrade,
) -> impl IntoResponse {
  ws.on_upgrade(async move |socket| {
    let Some((mut client_socket, user)) =
      super::user_ws_login(socket).await
    else {
      return;
    };

    let deployment = match get_check_permissions::<Deployment>(
      &deployment,
      &user,
      PermissionLevel::Read.terminal(),
    )
    .await
    {
      Ok(deployment) => deployment,
      Err(e) => {
        debug!("could not get deployment | {e:#}");
        let _ = client_socket
          .send(Message::text(format!("ERROR: {e:#}")))
          .await;
        let _ = client_socket.close().await;
        return;
      }
    };

    let server =
      match get::<Server>(&deployment.config.server_id).await {
        Ok(server) => server,
        Err(e) => {
          debug!("could not get server | {e:#}");
          let _ = client_socket
            .send(Message::text(format!("ERROR: {e:#}")))
            .await;
          let _ = client_socket.close().await;
          return;
        }
      };

    super::handle_container_attach_terminal(
      client_socket,
      &server,
      deployment.name,
      recreate,
    )
    .await
  })
}
