use libpso::packet::messages::*;
use libpso::packet::ship::*;
use crate::common::leveltable::CharacterStats;
use crate::ship::ship::{ShipError};
use crate::ship::items::{StackedFloorItem, FloorItem, CharacterBank};
use crate::ship::location::AreaClient;
use std::convert::TryInto;


pub fn item_drop(client: u8, target: u8, item_drop: &FloorItem) -> Result<ItemDrop, ShipError> {
    let item_bytes = item_drop.as_client_bytes();
    Ok(ItemDrop {
        client: client,
        target: target,
        area: item_drop.map_area().area_value(),
        variety: 0,
        unknown: 0,
        x: item_drop.x(),
        z: item_drop.z(),
        y: item_drop.y(),
        item_bytes: item_bytes[0..12].try_into()?,
        item_id: item_drop.item_id().0,
        item_bytes2: item_bytes[12..16].try_into()?,
        unknown2: 0,
    })
}

pub fn create_item(area_client: AreaClient, item: &FloorItem) -> Result<CreateItem, ShipError> {
    let bytes = item.as_client_bytes();
    Ok(CreateItem {
        client: area_client.local_client.id(),
        target: 0,
        item_data: bytes[0..12].try_into()?,
        item_id: item.item_id().0,
        item_data2: bytes[12..16].try_into()?,
        unknown: 0,
    })
}

pub fn remove_item_from_floor(area_client: AreaClient, item: &FloorItem) -> Result<RemoveItemFromFloor, ShipError> {
    Ok(RemoveItemFromFloor {
        client: area_client.local_client.id(),
        target: 0,
        client_id: area_client.local_client.id(),
        unknown: 0,
        area: item.map_area().area_value(),
        unknown2: 0,
        item_id: item.item_id().0,
    })
}

pub fn drop_split_stack(area_client: AreaClient, item: &StackedFloorItem) -> Result<DropSplitStack, ShipError> {
    let item_bytes = item.as_client_bytes();
    Ok(DropSplitStack {
        client: area_client.local_client.id(),
        target: 0,
        variety: 0,
        unknown1: 0,
        map_area: item.map_area.area_value(),
        x: item.x,
        z: item.z,
        item_bytes: item_bytes[0..12].try_into()?,
        item_id: item.item_id.0,
        item_bytes2: item_bytes[12..16].try_into()?,
        unknown2: 0,
    })
}

pub fn drop_split_meseta_stack(area_client: AreaClient, item: &FloorItem) -> Result<DropSplitStack, ShipError> {
    let item_bytes = item.as_client_bytes();
    Ok(DropSplitStack {
        client: area_client.local_client.id(),
        target: 0,
        variety: 0,
        unknown1: 0,
        map_area: item.map_area().area_value(),
        x: item.x(),
        z: item.z(),
        item_bytes: item_bytes[0..12].try_into()?,
        item_id: item.item_id().0,
        item_bytes2: item_bytes[12..16].try_into()?,
        unknown2: 0,
    })
}

pub fn character_gained_exp(area_client: AreaClient, exp: u32) -> GiveCharacterExp {
    GiveCharacterExp {
        client: area_client.local_client.id(),
        target: 0,
        exp: exp,
    }
}

pub fn character_leveled_up(area_client: AreaClient, level: u32, before_stats: CharacterStats, after_stats: CharacterStats) -> PlayerLevelUp {
    PlayerLevelUp {
        client: area_client.local_client.id(),
        target: 0,
        atp: after_stats.atp - before_stats.atp,
        mst: after_stats.mst - before_stats.mst,
        evp: after_stats.evp - before_stats.evp,
        hp: after_stats. hp - before_stats. hp,
        dfp: after_stats.dfp - before_stats.dfp,
        ata: after_stats.ata - before_stats.ata,
        lvl: level,
    }
}

// TOOD: meseta
pub fn bank_item_list(bank: &CharacterBank) -> BankItemList {
    BankItemList {
        aflag: 0,
        cmd: 0xBC,
        unknown: [0; 3],
        size: bank.count() as u32 * 0x18 + 0x14,
        checksum: 0x123434,
        item_count: bank.count() as u32,
        meseta: 12345,
        items: bank.as_client_bank_request()
    }
}