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;

pub fn player_chat(id: ClientId,
                   msg: &PlayerChat,
                   client_location: &ClientLocation,
                   clients: &Clients) -> Result<Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send>, ShipError> {
    let client = clients.get(&id).ok_or(ShipError::ClientNotFound(id))?;
    let cmsg = PlayerChat::new(client.user.id.0, msg.message.clone());

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

pub fn request_infoboard(id: ClientId,
                         client_location: &ClientLocation,
                         clients: &Clients)
                         -> Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send> {
    let area_clients = client_location.get_client_neighbors(id).unwrap();
    let r = area_clients.iter()
        .filter_map(|c| {
            clients.get(&c.client)
        })
        .map(|client| {
            InfoboardResponse {
                name: libpso::utf8_to_utf16_array!(client.character.name, 16),
                message: client.character.info_board.as_bytes(),
            }
        }).collect();
    Box::new(vec![(id, SendShipPacket::ViewInfoboardResponse(ViewInfoboardResponse {response: r}))].into_iter())
}

pub async fn write_infoboard<EG: EntityGateway>(id: ClientId,
                                          new_infoboard: &WriteInfoboard,
                                          clients: &mut Clients,
                                          mut entity_gateway: EG)
                       -> Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send> {
    let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id)).unwrap();
    client.character.info_board.update_infoboard(new_infoboard);
    entity_gateway.save_character(&client.character).await.unwrap();
    Box::new(None.into_iter())
}