use libpso::packet::ship::*;
use crate::common::serverstate::ClientId;
use crate::ship::ship::{SendShipPacket, ShipError, Clients};
use crate::ship::location::{ClientLocation};
use crate::entity::gateway::EntityGateway;

use futures::future::join_all;

pub async fn player_chat(id: ClientId,
                         msg: PlayerChat,
                         client_location: &ClientLocation,
                         clients: &Clients)
                         -> Result<Vec<(ClientId, SendShipPacket)>, ShipError> {
    let cmsg = clients.with(id, |client| Box::pin(async move {
        PlayerChat::new(client.user.id.0, msg.message)
    })).await?;

    Ok(client_location.get_all_clients_by_client(id).await.unwrap().into_iter()
       .map(move |client| {
           (client.client, SendShipPacket::PlayerChat(cmsg.clone()).clone())
       })
       .collect())
}

pub async fn request_infoboard(id: ClientId,
                               client_location: &ClientLocation,
                               clients: &Clients)
                               -> Result<Vec<(ClientId, SendShipPacket)>, ShipError> {
    let area_clients = client_location.get_client_neighbors(id).await.unwrap();
    let infoboards = join_all(
        area_clients.iter()
            .map(|client| async {
                clients.with(client.client, |client| Box::pin(async move {
                    InfoboardResponse {
                        name: libpso::utf8_to_utf16_array!(client.character.name, 16),
                        message: client.character.info_board.as_bytes(),
                    }
                })).await
            }))
        .await
        .into_iter()
        .collect::<Result<Vec<_>, ShipError>>()?;
    Ok(vec![(id, SendShipPacket::ViewInfoboardResponse(ViewInfoboardResponse {response: infoboards}))])
}

pub async fn write_infoboard<EG>(id: ClientId,
                                 new_infoboard: WriteInfoboard,
                                 clients: &Clients,
                                 entity_gateway: &mut EG)
                                 -> Result<Vec<(ClientId, SendShipPacket)>, ShipError>
where
    EG: EntityGateway + Clone + 'static,
{
    clients.with_mut(id, |client| {
        let mut entity_gateway = entity_gateway.clone();
        Box::pin(async move {
            client.character.info_board.update_infoboard(&new_infoboard);
            entity_gateway.save_character(&client.character).await
        })}).await??;
    Ok(Vec::new())
}