pub mod ability;
pub mod card;
pub mod color;
pub mod format;
pub mod turn;

use std::collections::{HashMap, VecDeque};
use std::fmt;

use ulid::Ulid;

pub use self::{
    ability::Stack,
    card::CardInstance,
    color::{Color, ColorBalance},
    turn::TurnState,
};

#[derive(Debug, Clone)]
pub struct PlayerInitDescriptor {
    balance: ColorBalance,
    deck: Vec<CardInstance>,
    guardians: Vec<CardInstance>,
}

impl From<(ColorBalance, Vec<CardInstance>, Vec<CardInstance>)> for PlayerInitDescriptor {
    fn from(
        (balance, deck, guardians): (ColorBalance, Vec<CardInstance>, Vec<CardInstance>),
    ) -> Self {
        Self {
            deck,
            guardians,
            balance,
        }
    }
}

/// Represents the data of a player
#[derive(Default, Debug, Clone)]
pub struct Player {
    id: Ulid,
    /// Is this player still in the game?
    is_active: bool,
    // TODO instead of a simple usize, allow for earmarking for certain purposes
    pub mana_pool: HashMap<Color, usize>,
    pub balance: ColorBalance,
    pub field: Field,
}

impl Player {
    pub fn id(&self) -> Ulid {
        self.id
    }
}

/// Wrapper that definitely refers to a hecs entity that *is* a card instance
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CardInstanced(hecs::Entity);

impl CardInstanced {}

/// Represents all the zones and places belonging to a player
#[derive(Debug, Default, Clone)]
pub struct Field {
    magister_place: Option<CardInstanced>,
    aide_places: [Option<CardInstanced>; 2],
    fragment_places: [Option<CardInstanced>; 6],
    // zones have no suffix
    deck: VecDeque<CardInstanced>,
    guardian_deck: VecDeque<CardInstanced>,
    hand: VecDeque<CardInstanced>,
    graveyard: VecDeque<CardInstanced>,
    exile: VecDeque<CardInstanced>,
}

#[derive(Default)]
pub struct Game {
    world: hecs::World,
    players: Vec<Player>,
    stack: Stack,
    turn: TurnState,
}

#[derive(thiserror::Error, Debug)]
pub enum GameCreationError {}

impl Game {
    pub fn new<I>(players: I) -> Result<Self, GameCreationError>
    where
        I: IntoIterator<Item = PlayerInitDescriptor>,
    {
        let mut game = Self::default();

        for (idx, player_desc) in players.into_iter().enumerate() {
            _ = idx;
            _ = player_desc;
            // Validate that player_dec is valid
            game.players.push(Player {
                id: Ulid::new(),
                is_active: true,
                mana_pool: HashMap::new(),
                balance: player_desc.balance,
                field: Field {
                    deck: vec![].into(),
                    guardian_deck: vec![].into(),
                    ..Default::default()
                },
            })
        }

        Ok(game)
    }

    pub fn players(&self) -> &[Player] {
        &self.players
    }

    pub fn players_mut(&mut self) -> &mut [Player] {
        &mut self.players
    }
}

impl fmt::Debug for Game {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("Game")
            .field("players", &self.players)
            .field("stack", &self.stack)
            .field("turn", &self.turn)
            .finish_non_exhaustive()
    }
}