use std::sync::Arc;

use serde::{Deserialize, Serialize};

use super::{Coord, Direction};

#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
pub struct Request {
    /// Game object describing the game being played.
    pub game: Game,
    /// Turn number for this move.
    pub turn: u32,
    /// Board object describing the initial state of the game board.
    pub board: Board,
    /// Battlesnake Object describing your Battlesnake.
    pub you: Battlesnake,
}

#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
pub struct Game {
    /// A unique identifier for this Game.
    pub id: Arc<str>,
    /// Information about the ruleset being used to run this Game.
    pub ruleset: Ruleset,
    /// The name of the map being played on.
    pub map: Arc<str>,
    /// How much time your snake has to respond to requests for this Game.
    pub timeout: u16,
    /// The source of this Game.
    /// One of:
    /// - tournament
    /// - league
    /// - arena
    /// - challenge
    /// - custom
    pub source: Arc<str>,
}

#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
pub struct Ruleset {
    /// Name of the ruleset being used to run this game.
    pub name: Arc<str>,
    /// The release version of the Rules module used in this game.
    pub version: Arc<str>,
    /// A collection of specific settings being used by the current game that control how the rules
    /// are applied.
    pub settings: Settings,
}

#[derive(Debug, PartialEq, Eq, Clone, Copy, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Settings {
    /// Percentage chance of spawning a new food every round.
    pub food_spawn_chance: u8,
    /// Minimum food to keep on the board every turn.
    pub minimum_food: u16,
    /// Health damage a snake will take when ending its turn in a hazard. This stacks on top of the
    /// regular 1 damage a snake takes per turn.
    pub hazard_damage_per_turn: u8,
    /// Settings for the royale game mode
    pub royale: RoyaleSettings,
}

#[derive(Debug, PartialEq, Eq, Clone, Copy, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct RoyaleSettings {
    /// The number of turns between generating new hazards (shrinking the safe board space).
    pub shrink_every_n_turns: u8,
}

#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
pub struct Board {
    /// The number of rows in the y-axis of the game board.
    pub height: u8,
    /// The number of rows in the x-axis of the game board.
    pub width: u8,
    /// Array of coordinates representing food locations on the game board.
    pub food: Vec<Coord>,
    /// Array of coordinates representing hazardous locations on the game board.
    pub hazards: Vec<Coord>,
    /// Array of Battlesnake objects representing all Battlesnakes remaining on the game board
    /// (including yourself if you haven't been eliminated).
    pub snakes: Vec<Battlesnake>,
}

#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
pub struct Battlesnake {
    /// Unique identifier for this Battlesnake in the context of the current Game.
    pub id: Arc<str>,
    /// Name given to this Battlesnake by its author
    pub name: Arc<str>,
    /// Health value of this Battlesnake, between 0 and 100
    pub health: u8,
    /// Array of coordinates representing the Battlesnake's location on the game board.
    /// This array is ordered from head to tail.
    pub body: Vec<Coord>,
    /// The previous response time of this Battlesnake, in milliseconds.
    /// If the Battlesnake timed out and failed to respond, the game timeout will be returned
    pub latency: Arc<str>,
    /// Coordinates for this Battlesnake's head.
    /// Equivalent to the first element of the body array.
    pub head: Coord,
    /// Length of this Battlesnake from head to tail.
    /// Equivalent to the length of the body array.
    pub length: u16,
    /// Message shouted by this Battlesnake on the previous turn
    pub shout: Option<Arc<str>>,
    /// The squad that the Battlesnake belongs to.
    /// Used to identify squad members in Squad Mode games.
    pub squad: Arc<str>,
}

#[derive(Debug, PartialEq, Eq, Clone, Serialize)]
pub struct Response {
    /// Your Battlesnake's move for this turn.
    #[serde(rename = "move")]
    pub direction: Direction,
    /// An optional message sent to all other Battlesnakes on the next turn.
    /// Must be 256 characters or less.
    pub shout: Option<String>,
}
