/*
    Hurry Curry! - a game about cooking
    Copyright (C) 2025 Hurry Curry! Contributors

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, version 3 of the License only.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.

*/
use crate::{Gamedata, Hand, ItemIndex, ItemLocation, PlayerID, Recipe, RecipeIndex, TileIndex};
use std::fmt::Display;

impl Gamedata {
    pub fn tile_name(&self, index: TileIndex) -> &str {
        &self.tile_names[index.0]
    }
    pub fn item_name(&self, index: ItemIndex) -> &str {
        &self.item_names[index.0]
    }
    pub fn recipe(&self, index: RecipeIndex) -> &Recipe {
        &self.recipes[index.0]
    }
    pub fn get_tile_by_name(&self, name: &str) -> Option<TileIndex> {
        self.tile_names
            .iter()
            .position(|t| t == name)
            .map(TileIndex)
    }
    pub fn get_item_by_name(&self, name: &str) -> Option<ItemIndex> {
        self.item_names
            .iter()
            .position(|t| t == name)
            .map(ItemIndex)
    }
    pub fn recipes(&self) -> impl Iterator<Item = (RecipeIndex, &Recipe)> {
        self.recipes
            .iter()
            .enumerate()
            .map(|(i, e)| (RecipeIndex(i), e))
    }
}

impl Recipe {
    pub fn tile(&self) -> Option<TileIndex> {
        match self {
            Recipe::Passive { tile, .. } => *tile,
            Recipe::Active { tile, .. } => *tile,
            Recipe::Instant { tile, .. } => *tile,
        }
    }
    pub fn speed(&self) -> Option<f32> {
        match self {
            Recipe::Passive { speed, .. } => Some(*speed),
            Recipe::Active { speed, .. } => Some(*speed),
            _ => None,
        }
    }
    pub fn revert_speed(&self) -> Option<f32> {
        match self {
            Recipe::Passive { revert_speed, .. } => *revert_speed,
            _ => None,
        }
    }
    pub fn warn(&self) -> bool {
        match self {
            Recipe::Passive { warn, .. } => *warn,
            _ => false,
        }
    }
    pub fn inputs(&self) -> Vec<ItemIndex> {
        match self {
            Recipe::Passive { input, .. } => vec![*input],
            Recipe::Active { input, .. } => vec![*input],
            Recipe::Instant { inputs, .. } => inputs.iter().flat_map(|e| e.to_owned()).collect(),
        }
    }
    pub fn outputs(&self) -> Vec<ItemIndex> {
        match self {
            Recipe::Passive { output, .. } => output.iter().copied().collect(),
            Recipe::Active { outputs, .. } => outputs.iter().flat_map(|e| e.to_owned()).collect(),
            Recipe::Instant { outputs, .. } => outputs.iter().flat_map(|e| e.to_owned()).collect(),
        }
    }
    pub fn supports_tile(&self, tile: Option<TileIndex>) -> bool {
        if let Some(tile_constraint) = self.tile() {
            if let Some(tile) = tile {
                tile == tile_constraint
            } else {
                false
            }
        } else {
            true
        }
    }
}

impl Display for ItemLocation {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            ItemLocation::Tile(pos) => write!(f, "tile({}, {})", pos.x, pos.y),
            ItemLocation::Player(player, hand) => write!(f, "{player}-{hand}"),
        }
    }
}

impl Display for Hand {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "hand#{}", self.0)
    }
}
impl Display for PlayerID {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "player#{}", self.0)
    }
}
impl Display for TileIndex {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "tile#{}", self.0)
    }
}
impl Display for ItemIndex {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "item#{}", self.0)
    }
}
impl Display for RecipeIndex {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "recipe#{}", self.0)
    }
}
