use libpso::packet::ship::PlayerChat;
use entity::gateway::EntityGateway;
use crate::common::serverstate::ClientId;
use crate::ship::ship::{ShipServerState, SendShipPacket};
use crate::ship::client::Clients;
use crate::ship::items::state::ItemState;
use entity::item::{BankName, BankIdentifier};
use crate::ship::packet::builder::message::bank_item_list;

async fn default_bank<'a, EG>(id: ClientId,
                              entity_gateway: &mut EG,
                              clients: &Clients,
                              item_state: &mut ItemState)
                              -> Result<Vec<(ClientId, SendShipPacket)>, String>
where
    EG: EntityGateway + Clone + 'static,
{
    let bank = clients
        .with_mut(id, |client| {
            let mut item_state = item_state.clone();
            let mut entity_gateway = entity_gateway.clone();

            Box::pin(async move {
                item_state.load_character_bank(&mut entity_gateway, &client.character, BankIdentifier::Character).await?;
                item_state.get_character_bank(&client.character).await
            })
        })
        .await
        .map_err(|err| format!("an error occured\n{err:?}"))?
        .map_err(|err| format!("an error occured\n{err:?}"))?;

    let bank_items_pkt = bank_item_list(&bank);
    Ok(vec![(id, SendShipPacket::BankItemList(bank_items_pkt))])
}

async fn switch_bank<'a, EG, T>(id: ClientId,
                                mut tokens: T,
                                entity_gateway: &mut EG,
                                clients: &Clients,
                                item_state: &mut ItemState)
                                -> Result<Vec<(ClientId, SendShipPacket)>, String>
where
    EG: EntityGateway + Clone + 'static,
    T: Iterator<Item = &'a str> + 'a,
{
    let bank_name = BankName(tokens.next().unwrap_or("").into());
    let bank = clients
        .with_mut(id, |client| {
            let mut item_state = item_state.clone();
            let mut entity_gateway = entity_gateway.clone();

            Box::pin(async move {
                item_state.load_character_bank(&mut entity_gateway, &client.character, BankIdentifier::Shared(bank_name)).await?;
                item_state.get_character_bank(&client.character).await
            })
        })
        .await
        .map_err(|err| format!("an error occured\n{err:?}"))?
        .map_err(|err| format!("an error occured\n{err:?}"))?;

    let bank_items_pkt = bank_item_list(&bank);
    Ok(vec![(id, SendShipPacket::BankItemList(bank_items_pkt))])
}


pub async fn handle_chat_command<EG>(id: ClientId,
                                     message: PlayerChat,
                                     state: &mut ShipServerState<EG>)
                                     -> Option<Result<Vec<(ClientId, SendShipPacket)>, String>>
where
    EG: EntityGateway + Clone + 'static,
{
    let mut tokens = message.message
        .trim_start_matches("\tJ")
        .trim_start_matches("\tE")
        .trim_end_matches('\0')
        .split_whitespace();
    let cmd = tokens.next()?;
    match cmd {
        "/bank" => Some(default_bank(id, &mut state.entity_gateway, &state.clients, &mut state.item_state).await),
        "/sbank" => Some(switch_bank(id, tokens, &mut state.entity_gateway, &state.clients, &mut state.item_state).await),

        _ => None,
    }
    
}