use crate::game::{
    character_sheet::*,
    chat_message::ChatMessage,
    entry::{ActionDefinition, ActionResult, DiceRoll, GameEntry},
};
use serde::{Deserialize, Serialize};
use tavern_macros::CharacterSheet;

pub mod entry;
use entry::{Entry, Weapon};

#[derive(Default, CharacterSheet, Serialize, Deserialize)]
pub struct Pathfinder2rCharacterSheet {
    // Genral stuff
    #[Input("Name")]
    #[Access(World)]
    name: String,
    #[Input("Weapons")]
    #[InputExpr(set_items, get_items)]
    weapon: [Option<Weapon>; 2],
    #[Input("Health")]
    #[Access(PartyMember)]
    health: i32,
    #[Input("Max Health")]
    #[Access(PartyMember)]
    max_health: i32,
    // Attributes
    #[Seperator]
    #[Input("Strength")]
    str: i32,
    #[Input("Dexterity")]
    dex: i32,
    #[Input("Constitution")]
    con: i32,
    #[Input("Intelligence")]
    int: i32,
    #[Input("Wisdom")]
    wis: i32,
    #[Input("Charisma")]
    cha: i32,
    // Skills
    #[Seperator]
    #[Field("Acrobatics")]
    #[Access(PartyMember)]
    #[FieldExpr(self.dex + self.acrobatics_prof * 2)]
    _acro: i32,
    #[Input("Acrobatics Prof")]
    acrobatics_prof: i32,
    #[Field("Arcana")]
    #[FieldExpr(self.int + self.arcana_prof * 2)]
    _arca: i32,
    #[Input("Arcana Prof")]
    arcana_prof: i32,
    #[Field("Crafting")]
    #[FieldExpr(self.int + self.crafting_prof * 2)]
    _crafting: i32,
    #[Input("Crafting Prof")]
    crafting_prof: i32,
    // TODO: Add more skills
    // TODO: Also add all the rest of the sheet items
}
impl Pathfinder2rCharacterSheet {
    fn set_items(&mut self, entry: EntryType) {
        if let EntryType::Array(a) = entry {
            let ws: Vec<Entry> = a.iter().map(|e| Entry::load(&e.as_text())).flatten().collect();
            self.weapon = [None, None];
            for w in ws {
                if let Entry::Weapon(w) = w {
                    if self.weapon[0].is_none() {
                        self.weapon[0] = Some(w);
                    } else if self.weapon[1].is_none() {
                        self.weapon[1] = Some(w);
                        break;
                    }
                }
            }
        } else {
            let s = entry.as_text();
            if let Some(Entry::Weapon(w)) = Entry::load(&s) {
                self.weapon[0] = Some(w);
                self.weapon[1] = None;
            }
        }
    }
    fn get_items(&self) -> EntryType {
        EntryType::Array(
            self.weapon
                .iter()
                .flatten()
                .map(|w| EntryType::Text(w.name.clone()))
                .collect(),
        )
    }
}
impl Character<Entry> for Pathfinder2rCharacterSheet {
    fn use_action(&mut self, entry: &Entry, action: &ActionResult) -> ChatMessage {
        match entry {
            Entry::Weapon(_) => ChatMessage::new("Attack".to_string())
                .with_action(ActionDefinition::new("Attack".to_string()).with_roll(DiceRoll::new(
                    "Piercing".to_string(),
                    12,
                    1,
                )))
                .with_action(ActionDefinition::new("Double".to_string()).with_roll(DiceRoll::new(
                    "Piercing".to_string(),
                    12,
                    2,
                ))),
            Entry::Consumable(_consumable) => {
                if action.name == "consume" {
                    ChatMessage::new("Heal".to_string()).with_action(
                        ActionDefinition::new("Heal".to_string())
                            .with_roll(DiceRoll::new("Heal".to_string(), 6, 0).constant(6)),
                    )
                } else {
                    todo!()
                }
            }
            Entry::Spell(_spell) => todo!(),
        }
    }

    fn actions(&self, entry: &Entry) -> Vec<ActionDefinition> {
        let v;
        match entry {
            Entry::Weapon(_) =>
            // should technically check if the item is in the user's packpack or something
            // but for now just return a constant list
            {
                v = vec![("wield", 0), ("attack", 1), ("drop", 0), ("stow", 0)]
            }
            Entry::Consumable(_) => v = vec![("consume", 0), ("stow", 0), ("drop", 0)],
            Entry::Spell(_) => v = vec![("cast", 1)],
        };
        v.iter()
            .map(|s| ActionDefinition {
                name: s.0.to_string(),
                targets: s.1,
                display_name: None,
                source: None,
                rolls: None,
            })
            .collect()
    }

    fn short(&self, id: usize) -> CharacterShort {
        CharacterShort {
            id,
            title: self.name.clone(),
            sub_title: Some("A Character!".to_string()),
            health: Some(
                ["Dying", "Hurt", "Harmed", "Unharmed"][((self.health * 4) / self.max_health) as usize].to_string(),
            ),
            level: Some(1),
        }
    }
}
