use alloc::{vec::Vec, string::{String, ToString}, collections::{BTreeMap}, boxed::Box, borrow::ToOwned, fmt, format};
use serde::{Serialize, Deserialize, Deserializer, de, Serializer};
use serde::de::{Visitor, Error, IntoDeserializer, MapAccess};
use serde::ser::SerializeMap;
use serde_json::Value;
use crate::{SerializeResult, DeserializeResult};

pub type BoxedChat = Box<Chat>;

#[derive(Clone, Debug, PartialEq)]
pub enum Chat {
    Text(TextComponent),
    Translation(TranslationComponent),
    Keybind(KeybindComponent),
    Score(ScoreComponent),
}

impl Chat {
    pub fn base(&self) -> &BaseComponent {
        use Chat::*;

        match self {
            Text(body) => &body.base,
            Translation(body) => &body.base,
            Keybind(body) => &body.base,
            Score(body) => &body.base,
        }
    }

    pub fn siblings(&self) -> &Vec<BoxedChat> {
        &self.base().extra
    }

    pub fn boxed(self) -> BoxedChat {
        Box::new(self)
    }

    pub fn from_text(text: &str) -> Chat {
        Chat::Text(TextComponent {
            base: BaseComponent::default(),
            text: text.to_owned(),
        })
    }

    pub fn from_traditional(orig: &str, translate_colorcodes: bool) -> Chat {
        TraditionalParser::new(orig, translate_colorcodes).parse()
    }

    pub fn to_traditional(&self) -> Option<String> {
        use Chat::*;

        match self {
            Text(body) => Some(body.to_traditional()),
            _ => None
        }
    }
}

struct TraditionalParser {
    source: Vec<char>,
    at: usize,
    translate_colorcodes: bool,

    // state
    text: String,
    color: Option<ColorCode>,
    bold: bool,
    italic: bool,
    underlined: bool,
    strikethrough: bool,
    obfuscated: bool,

    // all the parts we've already seen
    done: Vec<TextComponent>,
}

impl TraditionalParser {

    fn new(source: &str, translate_colorcodes: bool) -> Self {
        Self {
            source: source.chars().collect(),
            at: 0,
            translate_colorcodes,

            text: String::new(),
            color: None,
            bold: false,
            italic: false,
            underlined: false,
            strikethrough: false,
            obfuscated: false,

            done: Vec::new(),
        }
    }

    fn parse(mut self) -> Chat {
        loop {
            if let Some(formatter) = self.consume_formatter() {
                self.handle_formatter(formatter)
            } else if let Some(next) = self.consume_char() {
                self.push_next(next)
            } else {
                return self.finalize()
            }
        }
    }

    fn handle_formatter(&mut self, formatter: Formatter) {
        use Formatter::*;

        if self.has_text() {
            self.finish_current();
        }

        match formatter {
            Color(color) => {
                self.finish_current();
                self.color = Some(color);
            }
            Obfuscated => self.obfuscated = true,
            Bold => self.bold = true,
            Strikethrough => self.strikethrough = true,
            Underline => self.underlined = true,
            Italic => self.italic = true,
            _ => {}
        }
    }

    fn push_next(&mut self, next: char) {
        self.text.push(next);
    }

    fn finish_current(&mut self) {
        if self.has_text() {
            let current = TextComponent {
                text: self.text.clone(),
                base: BaseComponent {
                    color: self.color.clone(),
                    bold: self.bold,
                    italic: self.italic,
                    underlined: self.underlined,
                    strikethrough: self.strikethrough,
                    obfuscated: self.obfuscated,
                    hover_event: None,
                    click_event: None,
                    insertion: None,
                    extra: Vec::default()
                }
            };
            self.text.clear();
            self.done.push(current);
        }

        self.reset_style();
    }

    fn reset_style(&mut self) {
        self.bold = false;
        self.italic = false;
        self.underlined = false;
        self.strikethrough = false;
        self.obfuscated = false;
        self.color = None;
    }

    fn has_text(&self) -> bool {
        return !self.text.is_empty()
    }

    fn is_on_formatter(&self) -> bool {
        self.source.get(self.at).map(move |c| {
            let c = *c;
            c == SECTION_SYMBOL || (self.translate_colorcodes && c == '&')
        }).unwrap_or(false)
    }

    fn consume_char(&mut self) -> Option<char> {
        if let Some(c) = self.source.get(self.at) {
            self.at += 1;
            Some(*c)
        } else {
            None
        }
    }

    fn consume_formatter(&mut self) -> Option<Formatter> {
        if self.is_on_formatter() {
            self.consume_char()?;
            let c = self.consume_char()?;
            let out = Formatter::from_code(&c);
            if out.is_none() {
                self.at -= 1;
            }

            out
        } else {
            None
        }
    }

    fn finalize(mut self) -> Chat {
        self.finish_current();
        self.simplify();
        let n_components = self.done.len();
        if n_components == 1 {
            return Chat::Text(self.done.remove(0));
        }

        let mut top_level = TextComponent {
            text: String::default(),
            base: BaseComponent::default(),
        };

        if n_components > 0 {
            top_level.base.extra.extend(
                self.done.into_iter()
                    .map(move |component| Chat::Text(component).boxed()));
        }

        Chat::Text(top_level)
    }

    fn simplify(&mut self) {
        let mut updated = Vec::with_capacity(self.done.len());
        let mut last: Option<TextComponent> = None;
        while !self.done.is_empty() {
            let cur = self.done.remove(0);
            if let Some(mut la) = last.take() {
                if la.base.has_same_style_as(&cur.base) {
                    la.text.extend(cur.text.chars());
                    last = Some(la);
                    continue;
                } else {
                    updated.push(la);
                }
            }

            last = Some(cur);
        }

        if let Some(l) = last.take() {
            updated.push(l);
        }

        self.done = updated;
    }
}

#[derive(Serialize, Clone, Debug, PartialEq)]
pub struct BaseComponent {
    #[serde(skip_serializing_if = "should_skip_flag_field")]
    pub bold: bool,
    #[serde(skip_serializing_if = "should_skip_flag_field")]
    pub italic: bool,
    #[serde(skip_serializing_if = "should_skip_flag_field")]
    pub underlined: bool,
    #[serde(skip_serializing_if = "should_skip_flag_field")]
    pub strikethrough: bool,
    #[serde(skip_serializing_if = "should_skip_flag_field")]
    pub obfuscated: bool,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub color: Option<ColorCode>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub insertion: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub click_event: Option<ChatClickEvent>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub hover_event: Option<ChatHoverEvent>,
    #[serde(skip_serializing_if = "Vec::is_empty")]
    pub extra: Vec<BoxedChat>,
}

fn should_skip_flag_field(flag: &bool) -> bool {
    !*flag
}

impl BaseComponent {

    fn has_same_style_as(&self, other: &Self) -> bool {
        other.bold == self.bold &&
            other.italic == self.italic &&
            other.underlined == self.underlined &&
            other.strikethrough == self.strikethrough &&
            other.obfuscated == self.obfuscated &&
            other.color.eq(&self.color)
    }
}

impl Into<BaseComponent> for JsonComponentBase {
    fn into(self) -> BaseComponent {
        BaseComponent {
            bold: self.bold.unwrap_or(false),
            italic: self.italic.unwrap_or(false),
            underlined: self.underlined.unwrap_or(false),
            strikethrough: self.strikethrough.unwrap_or(false),
            obfuscated: self.obfuscated.unwrap_or(false),
            color: self.color,
            insertion: self.insertion,
            click_event: self.click_event,
            hover_event: self.hover_event,
            extra: self.extra.into_iter().map(move |elem| elem.boxed()).collect(),
        }
    }
}

#[derive(Deserialize)]
struct JsonComponentBase {
    pub bold: Option<bool>,
    pub italic: Option<bool>,
    pub underlined: Option<bool>,
    pub strikethrough: Option<bool>,
    pub obfuscated: Option<bool>,
    pub color: Option<ColorCode>,
    pub insertion: Option<String>,
    #[serde(rename = "clickEvent")]
    pub click_event: Option<ChatClickEvent>,
    #[serde(rename = "hoverEvent")]
    pub hover_event: Option<ChatHoverEvent>,
    #[serde(default = "Vec::default")]
    pub extra: Vec<Chat>,

    #[serde(flatten)]
    _additional: BTreeMap<String, serde_json::Value>
}

impl Default for BaseComponent {
    fn default() -> Self {
        Self {
            bold: false,
            italic: false,
            underlined: false,
            strikethrough: false,
            obfuscated: false,
            color: None,
            insertion: None,
            click_event: None,
            hover_event: None,
            extra: Vec::default(),
        }
    }
}

#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)]
pub struct TextComponent {
    pub text: String,

    #[serde(flatten)]
    #[serde(skip_deserializing)]
    pub base: BaseComponent,
}

impl TextComponent {
    pub fn to_traditional(&self) -> String {
        let b = &self.base;
        let text = &self.text;

        let (mut buf, has_formatters) = if !text.is_empty() {
            let formatters = self.traditional_formatters(false);
            let has_formatters = formatters.is_some();
            let mut buf = formatters.unwrap_or_else(|| String::new());
            buf.extend(text.chars());
            (buf, has_formatters)
        } else {
            (String::default(), false)
        };

        let mut last_had_formatters = has_formatters;
        for extra in b.extra.iter() {
            if let Chat::Text(child) = extra.as_ref() {
                match child.traditional_formatters(last_had_formatters) {
                    Some(child_fmts) => {
                        last_had_formatters = true;
                        buf.extend(child_fmts.chars())
                    },
                    None => {
                        last_had_formatters = false;
                    }
                }

                buf.extend(child.text.chars());
            }
        }

        buf
    }

    fn traditional_formatters(&self, prev_colored: bool) -> Option<String> {
        let b = &self.base;
        let mut buf = String::default();

        if let Some(c) = b.color {
            buf.push(SECTION_SYMBOL);
            buf.push(c.code());
        }

        let mut apply_formatter = |b: bool, formatter: Formatter| {
            if b {
                buf.push(SECTION_SYMBOL);
                buf.push(formatter.code());
            }
        };

        apply_formatter(b.bold, Formatter::Bold);
        apply_formatter(b.italic, Formatter::Italic);
        apply_formatter(b.strikethrough, Formatter::Strikethrough);
        apply_formatter(b.underlined, Formatter::Underline);
        apply_formatter(b.obfuscated, Formatter::Obfuscated);

        if buf.is_empty() {
            if prev_colored {
                buf.push(SECTION_SYMBOL);
                buf.push('r');
                Some(buf)
            } else {
                None
            }
        } else {
            Some(buf)
        }
    }
}

#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)]
pub struct TranslationComponent {
    pub translate: String,
    #[serde(skip_serializing_if = "Vec::is_empty")]
    pub with: Vec<BoxedChat>,

    #[serde(flatten)]
    #[serde(skip_deserializing)]
    pub base: BaseComponent,
}

#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)]
pub struct KeybindComponent {
    pub keybind: String,

    #[serde(flatten)]
    #[serde(skip_deserializing)]
    pub base: BaseComponent
}
#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)]
pub struct ScoreComponent {
    pub score: ScoreComponentObjective,

    #[serde(flatten)]
    #[serde(skip_deserializing)]
    pub base: BaseComponent
}

#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)]
pub struct ScoreComponentObjective {
    pub name: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub objective: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub value: Option<String>,
}

#[derive(Clone, Debug, PartialEq)]
pub enum ChatClickEvent {
    OpenUrl(String),
    RunCommand(String),
    SuggestCommand(String),
    ChangePage(i32)
}

impl Serialize for ChatClickEvent {
    fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error> where
        S: Serializer
    {
        let mut m = serializer.serialize_map(Some(2))?;

        use ChatClickEvent::*;

        m.serialize_entry("action", match self {
            OpenUrl(_) => "open_url",
            RunCommand(_) => "run_command",
            SuggestCommand(_) => "suggest_command",
            ChangePage(_) => "change_page",
        })?;

        m.serialize_key("value")?;

        match self {
            OpenUrl(body) => m.serialize_value(body),
            RunCommand(body) => m.serialize_value(body),
            SuggestCommand(body) => m.serialize_value(body),
            ChangePage(body) => m.serialize_value(body),
        }?;

        m.end()
    }
}

impl<'de> Deserialize<'de> for ChatClickEvent {
    fn deserialize<D>(deserializer: D) -> Result<Self, <D as Deserializer<'de>>::Error> where
        D: Deserializer<'de>
    {
        struct V;

        impl<'de> Visitor<'de> for V {
            type Value = ChatClickEvent;

            fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                write!(f, "an event object for ChatClickEvent")
            }

            fn visit_map<A>(self, mut map: A) -> Result<Self::Value, <A as MapAccess<'de>>::Error> where
                A: MapAccess<'de>
            {
                let (action, value) = read_event(&mut map)?;

                use ChatClickEvent::*;
                match action {
                    "open_url" => match value.as_str() {
                        Some(url) => Ok(OpenUrl(url.to_owned())),
                        None => Err(A::Error::custom(format!("open_url requires string body, got {}", value)))
                    },
                    "run_command" => match value.as_str() {
                        Some(cmd) => Ok(RunCommand(cmd.to_owned())),
                        None => Err(A::Error::custom(format!("run_command requires string body, got {}", value)))
                    },
                    "suggest_command" => match value.as_str() {
                        Some(cmd) => Ok(SuggestCommand(cmd.to_owned())),
                        None => Err(A::Error::custom(format!("suggest_command requires string body, got {}", value)))
                    },
                    "change_page" => match value.as_i64() {
                        Some(v) => Ok(ChangePage(v as i32)),
                        None => Err(A::Error::custom(format!("change_page requires integer body, got {}", value)))
                    },
                    other => Err(A::Error::custom(format!("invalid click action kind {}", other)))
                }
            }
        }

        deserializer.deserialize_map(V)
    }
}

#[derive(Clone, Debug, PartialEq)]
pub enum ChatHoverEvent {
    ShowText(BoxedChat),
    ShowItem(Value),
    ShowEntity(Value)
}

impl Serialize for ChatHoverEvent {
    fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error> where
        S: Serializer
    {
        let mut m = serializer.serialize_map(Some(2))?;

        use ChatHoverEvent::*;

        m.serialize_entry("action", match self {
            ShowText(_) => "show_text",
            ShowItem(_) => "show_item",
            ShowEntity(_) => "show_entity",
        })?;

        m.serialize_key("value")?;

        match self {
            ShowText(body) => m.serialize_value(body),
            ShowItem(body) => m.serialize_value(body),
            ShowEntity(body) => m.serialize_value(body),
        }?;

        m.end()
    }
}

impl<'de> Deserialize<'de> for ChatHoverEvent {
    fn deserialize<D>(deserializer: D) -> Result<Self, <D as Deserializer<'de>>::Error> where
        D: Deserializer<'de>
    {
        struct V;

        impl<'de> Visitor<'de> for V {
            type Value = ChatHoverEvent;

            fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                write!(f, "an event object for ChatClickEvent")
            }

            //noinspection ALL
            fn visit_map<A>(self, mut map: A) -> Result<Self::Value, <A as MapAccess<'de>>::Error> where
                A: MapAccess<'de>
            {
                let (action, value) = read_event(&mut map)?;

                use ChatHoverEvent::*;
                match action {
                    "show_text" => Ok(ShowText(
                        Chat::deserialize(value.into_deserializer())
                            .map_err(move |err| A::Error::custom(
                                format!("error deserializing text to show {:?}", err)))?
                            .boxed())),
                    "show_item" => Ok(ShowItem(value)),
                    "show_entity" => Ok(ShowEntity(value)),
                    other => Err(A::Error::custom(format!("invalid hover action kind {}", other)))
                }
            }
        }

        deserializer.deserialize_map(V)
    }
}

pub const SECTION_SYMBOL: char = '§';

#[derive(PartialOrd, PartialEq, Debug, Copy, Clone)]
pub enum ColorCode {
    Black,
    DarkBlue,
    DarkGreen,
    DarkAqua,
    DarkRed,
    DarkPurple,
    Gold,
    Gray,
    DarkGray,
    Blue,
    Green,
    Aqua,
    Red,
    LightPurple,
    Yellow,
    White,
}

impl ColorCode {
    pub fn from_code(i: &char) -> Option<Self> {
        match i {
            '0' => Some(ColorCode::Black),
            '1' => Some(ColorCode::DarkBlue),
            '2' => Some(ColorCode::DarkGreen),
            '3' => Some(ColorCode::DarkAqua),
            '4' => Some(ColorCode::DarkRed),
            '5' => Some(ColorCode::DarkPurple),
            '6' => Some(ColorCode::Gold),
            '7' => Some(ColorCode::Gray),
            '8' => Some(ColorCode::DarkGray),
            '9' => Some(ColorCode::Blue),
            'a' => Some(ColorCode::Green),
            'b' => Some(ColorCode::Aqua),
            'c' => Some(ColorCode::Red),
            'd' => Some(ColorCode::LightPurple),
            'e' => Some(ColorCode::Yellow),
            'f' => Some(ColorCode::White),
            _ => None,
        }
    }

    pub fn code(&self) -> char {
        match self {
            ColorCode::Black => '0',
            ColorCode::DarkBlue => '1',
            ColorCode::DarkGreen => '2',
            ColorCode::DarkAqua => '3',
            ColorCode::DarkRed => '4',
            ColorCode::DarkPurple => '5',
            ColorCode::Gold => '6',
            ColorCode::Gray => '7',
            ColorCode::DarkGray => '8',
            ColorCode::Blue => '9',
            ColorCode::Green => 'a',
            ColorCode::Aqua => 'b',
            ColorCode::Red => 'c',
            ColorCode::LightPurple => 'd',
            ColorCode::Yellow => 'e',
            ColorCode::White => 'f',
        }
    }

    pub fn from_name(name: &str) -> Option<Self> {
        match name.to_ascii_lowercase().as_str() {
            "black" => Some(ColorCode::Black),
            "dark_blue" => Some(ColorCode::DarkBlue),
            "dark_green" => Some(ColorCode::DarkGreen),
            "dark_aqua" => Some(ColorCode::DarkAqua),
            "dark_red" => Some(ColorCode::DarkRed),
            "dark_purple" => Some(ColorCode::DarkPurple),
            "gold" => Some(ColorCode::Gold),
            "gray" => Some(ColorCode::Gray),
            "dark_gray" => Some(ColorCode::DarkGray),
            "blue" => Some(ColorCode::Blue),
            "green" => Some(ColorCode::Green),
            "aqua" => Some(ColorCode::Aqua),
            "red" => Some(ColorCode::Red),
            "light_purple" => Some(ColorCode::LightPurple),
            "yellow" => Some(ColorCode::Yellow),
            "white" => Some(ColorCode::White),
            _ => None,
        }
    }

    pub fn name(&self) -> &str {
        match self {
            ColorCode::Black => "black",
            ColorCode::DarkBlue => "dark_blue",
            ColorCode::DarkGreen => "dark_green",
            ColorCode::DarkAqua => "dark_aqua",
            ColorCode::DarkRed => "dark_red",
            ColorCode::DarkPurple => "dark_purple",
            ColorCode::Gold => "gold",
            ColorCode::Gray => "gray",
            ColorCode::DarkGray => "dark_gray",
            ColorCode::Blue => "blue",
            ColorCode::Green => "green",
            ColorCode::Aqua => "aqua",
            ColorCode::Red => "red",
            ColorCode::LightPurple => "light_purple",
            ColorCode::Yellow => "yellow",
            ColorCode::White => "white",
        }
    }
}

impl fmt::Display for ColorCode {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}{}", SECTION_SYMBOL, self.code())
    }
}

impl Serialize for ColorCode {
    fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error> where
        S: Serializer {
        serializer.serialize_str(self.name())
    }
}

impl<'de> Deserialize<'de> for ColorCode {
    fn deserialize<D>(deserializer: D) -> Result<Self, <D as Deserializer<'de>>::Error> where
        D: Deserializer<'de>
    {
        struct V;

        impl<'de> Visitor<'de> for V {
            type Value = ColorCode;

            fn expecting(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
                write!(fmt, "a string representing a color code")
            }

            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> where
                E: de::Error,
            {
                if let Some(code) = ColorCode::from_name(v) {
                    Ok(code)
                } else {
                    Err(E::custom(format!("invalid color code name {}", v)))
                }
            }
        }

        deserializer.deserialize_str(V)
    }
}

#[derive(PartialOrd, PartialEq, Debug, Copy, Clone)]
pub enum Formatter {
    Color(ColorCode),
    Obfuscated,
    Bold,
    Strikethrough,
    Underline,
    Italic,
    Reset,
}

impl Formatter {
    pub fn from_code(i: &char) -> Option<Self> {
        match i.to_ascii_lowercase() {
            'k' => Some(Formatter::Obfuscated),
            'l' => Some(Formatter::Bold),
            'm' => Some(Formatter::Strikethrough),
            'n' => Some(Formatter::Underline),
            'o' => Some(Formatter::Italic),
            'r' => Some(Formatter::Reset),
            _ => ColorCode::from_code(i).map(Formatter::Color),
        }
    }

    pub fn code(&self) -> char {
        match self {
            Formatter::Color(c) => c.code(),
            Formatter::Obfuscated => 'k',
            Formatter::Bold => 'l',
            Formatter::Strikethrough => 'm',
            Formatter::Underline => 'n',
            Formatter::Italic => 'o',
            Formatter::Reset => 'r',
        }
    }

    pub fn from_name(name: &str) -> Option<Self> {
        match name.to_ascii_lowercase().as_str() {
            "obfuscated" => Some(Formatter::Obfuscated),
            "bold" => Some(Formatter::Bold),
            "strikethrough" => Some(Formatter::Strikethrough),
            "underline" => Some(Formatter::Underline),
            "italic" => Some(Formatter::Italic),
            "reset" => Some(Formatter::Reset),
            _ => ColorCode::from_name(name).map(Formatter::Color),
        }
    }

    pub fn name(&self) -> &str {
        match self {
            Formatter::Obfuscated => "obfuscated",
            Formatter::Bold => "bold",
            Formatter::Strikethrough => "strikethrough",
            Formatter::Underline => "underline",
            Formatter::Italic => "italic",
            Formatter::Reset => "reset",
            Formatter::Color(c) => c.name(),
        }
    }
}

impl fmt::Display for Formatter {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}{}", SECTION_SYMBOL, self.code())
    }
}


impl<'de> Deserialize<'de> for Chat {
    fn deserialize<D>(deserializer: D) -> Result<Self, <D as Deserializer<'de>>::Error> where
        D: Deserializer<'de>
    {
        struct V;

        impl<'de> Visitor<'de> for V {
            type Value = Chat;

            fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
                write!(formatter, "any primitive or a JSON object specifying the component")
            }

            fn visit_bool<E>(self, value: bool) -> Result<Self::Value, E> where E: de::Error {
                self.visit_string(value.to_string())
            }

            fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E> where E: de::Error {
                self.visit_string(value.to_string())
            }

            fn visit_f64<E>(self, value: f64) -> Result<Self::Value, E> where E: de::Error {
                self.visit_string(value.to_string())
            }

            fn visit_str<E>(self, value: &str) -> Result<Self::Value, E> where E: de::Error {
                Ok(Chat::Text(TextComponent {
                    base: BaseComponent::default(),
                    text: value.to_owned(),
                }))
            }

            fn visit_map<M>(self, map: M) -> Result<Self::Value, M::Error> where M: de::MapAccess<'de> {
                let mut base: JsonComponentBase = de::Deserialize::deserialize(de::value::MapAccessDeserializer::new(map))?;
                let additional = &mut base._additional;

                // string component
                if let Some(raw_text) = additional.remove("text") {
                    return if let Some(text) = raw_text.as_str() {
                        additional.clear();
                        Ok(Chat::Text(TextComponent {
                            text: text.to_owned(),
                            base: base.into(),
                        }))
                    } else {
                        Err(M::Error::custom(format!("have text but it's not a string - {:?}", raw_text)))
                    };
                }

                // translate
                if let Some(raw_translate) = additional.remove("translate") {
                    return if let Some(translate) = raw_translate.as_str() {
                        // need "with"
                        if let Some(raw_with) = additional.remove("with") {
                            if let Some(withs) = raw_with.as_array() {
                                let mut withs_out = Vec::with_capacity(withs.len());
                                for with in withs {
                                    withs_out.push(with.deserialize_any(V)
                                        .map_err(move |err| M::Error::custom(
                                            format!("unable to parse one of the translation with entries :: {}", err)))?
                                        .boxed());
                                }
                                Ok(Chat::Translation(TranslationComponent{
                                    base: base.into(),
                                    translate: translate.to_owned(),
                                    with: withs_out,
                                }))
                            } else {
                                Err(M::Error::custom(format!("have with but it's not an array - {:?}", raw_with)))
                            }
                        } else {
                            Ok(Chat::Translation(TranslationComponent{
                                base: base.into(),
                                translate: translate.to_owned(),
                                with: Vec::default(),
                            }))
                        }
                    } else {
                        Err(M::Error::custom(format!("have translate but it's not a string - {:?}", raw_translate)))
                    }
                }

                // keybind
                if let Some(raw_keybind) = additional.remove("keybind") {
                    return if let Some(keybind) = raw_keybind.as_str() {
                        Ok(Chat::Keybind(KeybindComponent{
                            keybind: keybind.to_owned(),
                            base: base.into()
                        }))
                    } else {
                        Err(M::Error::custom(format!("have keybind but it's not a string! {:?}", raw_keybind)))
                    }
                }

                // score
                if let Some(raw_score) = additional.remove("score") {
                    let score = ScoreComponentObjective::deserialize(raw_score.into_deserializer())
                        .map_err(move |err| M::Error::custom(
                            format!("failed to deserialize scoreboard objective for score chat component :: {:?}", err)))?;

                    return Ok(Chat::Score(ScoreComponent{
                        score,
                        base: base.into(),
                    }));
                }

                // selector (SKIP)

                Err(M::Error::custom("not able to parse chat component, not a valid chat component kind"))
            }
        }

        deserializer.deserialize_any(V)
    }
}

impl Serialize for Chat {
    fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error> where
        S: Serializer
    {
        use Chat::*;

        match self {
            Text(body) => body.serialize(serializer),
            Translation(body) => body.serialize(serializer),
            Keybind(body) => body.serialize(serializer),
            Score(body) => body.serialize(serializer)
        }
    }
}

impl super::Serialize for Chat {
    fn mc_serialize<S: super::Serializer>(&self, to: &mut S) -> SerializeResult {
        serde_json::to_string(self)
            .map_err(move |err| super::SerializeErr::FailedJsonEncode(
                format!("error while encoding chat :: {:?} -> {:?}", self, err)))?
            .mc_serialize(to)
    }
}

impl super::Deserialize for Chat {
    fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> {
        String::mc_deserialize(data)?.try_map(move |raw| {
            serde_json::from_str(raw.as_str()).map_err(move |err|
                super::DeserializeErr::FailedJsonDeserialize(format!(
                    "failed to deserialize chat from JSON '{}' :: {:?}", raw, err
                )))
        })
    }
}

#[cfg(all(test, feature = "std"))]
use super::protocol::TestRandom;

#[cfg(all(test, feature = "std"))]
impl TestRandom for Chat {
    fn test_gen_random() -> Self {
        let str = String::test_gen_random();
        Chat::from_text(str.as_str())
    }
}

fn read_event<'de, A>(
    access: &mut A,
) -> Result<(&'de str, Value), <A as MapAccess<'de>>::Error>
    where A: MapAccess<'de>
{
    let mut action: Option<&str> = None;
    let mut value: Option<Value> = None;
    while action.is_none() || value.is_none() {
        if let Some(key) = access.next_key()? {
            match key {
                "action" => {
                    action = access.next_value()?;
                    if action.is_none() {
                        return Err(A::Error::custom("none for value key=action"));
                    }
                },
                "value" => {
                    value = access.next_value()?;
                    if value.is_none() {
                        return Err(A::Error::custom("none for value key=value"));
                    }
                },
                other => {
                    return Err(A::Error::custom(format!("unexpected key in event {}", other)));
                }
            }
        } else {
            return Err(A::Error::custom(format!("event needs action and value")));
        }
    }

    Ok((action.expect("checked"), value.expect("checked")))
}

#[cfg(test)]
pub mod tests {

    use super::*;

    #[test]
    fn test_from_traditional_simple() {
        let out = Chat::from_traditional("&cthis &cis red, and &rthis is &e&lyellow", true);
        assert_eq!(out, Chat::Text(TextComponent{
            text: String::default(),
            base: {
                let mut b = BaseComponent::default();
                b.extra = alloc::vec!(
                    Chat::Text(TextComponent{
                        text: "this is red, and ".to_owned(),
                        base: {
                            let mut b = BaseComponent::default();
                            b.color = Some(ColorCode::Red);
                            b
                        },
                    }).boxed(),
                    Chat::Text(TextComponent{
                        text: "this is ".to_owned(),
                        base: BaseComponent::default(),
                    }).boxed(),
                    Chat::Text(TextComponent{
                        text: "yellow".to_owned(),
                        base: {
                            let mut b = BaseComponent::default();
                            b.color = Some(ColorCode::Yellow);
                            b.bold = true;
                            b
                        }
                    }).boxed()
                );
                b
            }
        }));

        let traditional = out.to_traditional().expect("is text");
        assert_eq!(traditional.as_str(), "§cthis is red, and §rthis is §e§lyellow");
        #[cfg(feature="std")]
        println!("{}", serde_json::to_string_pretty(&out).expect("should serialize fine"));
    }
}