use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Config {
    pub prefs: Option<Preferences>,
    pub language: Option<String>,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Preferences {
    pub dark: Option<bool>,
    pub transp: Option<bool>,
    pub bg_img: Option<String>,
    pub is_3d: Option<bool>,
    pub theme: Option<Theme>,
    pub piece_set: Option<PieceSet>,
    pub theme_3d: Option<Theme3d>,
    pub piece_set_3d: Option<PieceSet3d>,
    pub sound_set: Option<SoundSet>,
    pub blindfold: Option<i32>,
    pub auto_queen: Option<i32>,
    pub auto_threefold: Option<i32>,
    pub takeback: Option<i32>,
    pub moretime: Option<i32>,
    pub clock_tenths: Option<i32>,
    pub clock_bar: Option<bool>,
    pub clock_sound: Option<bool>,
    pub premove: Option<bool>,
    pub animation: Option<i32>,
    pub piece_notation: Option<i32>,
    pub captured: Option<bool>,
    pub follow: Option<bool>,
    pub highlight: Option<bool>,
    pub destination: Option<bool>,
    pub coords: Option<i32>,
    pub replay: Option<i32>,
    pub challenge: Option<i32>,
    pub message: Option<i32>,
    pub submit_move: Option<i32>,
    pub confirm_resign: Option<i32>,
    pub insight_share: Option<i32>,
    pub keyboard_move: Option<i32>,
    pub voice_move: Option<bool>,
    pub zen: Option<i32>,
    pub ratings: Option<i32>,
    pub move_event: Option<i32>,
    pub rook_castle: Option<i32>,
    pub flairs: Option<bool>,
    /// 0 = No, 1 = When losing, 2 = When losing or drawing
    #[serde(rename = "sayGG")]
    pub say_gg: Option<i32>,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum Theme {
    Blue,
    Blue2,
    Blue3,
    BlueMarble,
    Canvas,
    Wood,
    Wood2,
    Wood3,
    Wood4,
    Maple,
    Maple2,
    Brown,
    Leather,
    Green,
    Marble,
    GreenPlastic,
    Grey,
    Metal,
    Olive,
    Newspaper,
    Purple,
    PurpleDiag,
    Pink,
    Ic,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum PieceSet {
    Cburnett,
    Merida,
    Alpha,
    Pirouetti,
    Chessnut,
    Chess7,
    Reillycraig,
    Companion,
    Riohacha,
    Kosal,
    Leipzig,
    Fantasy,
    Spatial,
    California,
    Pixel,
    Maestro,
    Fresca,
    Cardinal,
    Gioco,
    Tatiana,
    Staunty,
    Governor,
    Dubrovny,
    IcPieces,
    Shapes,
    Letter,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum Theme3d {
    BlackWhiteAluminium,
    BrushedAluminium,
    ChinaBlue,
    ChinaGreen,
    ChinaGrey,
    ChinaScarlet,
    ClassicBlue,
    GoldSilver,
    LightWood,
    PowerCoated,
    Rosewood,
    Marble,
    Wax,
    Jade,
    Woodi,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum PieceSet3d {
    Basic,
    Wood,
    Metal,
    RedVBlue,
    ModernJade,
    ModernWood,
    Glass,
    Trimmed,
    Experimental,
    Staunton,
    CubesAndPi,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum SoundSet {
    Silent,
    Standard,
    Piano,
    Nes,
    Sfx,
    Futuristic,
    Robot,
    Music,
    Speech,
}

#[cfg(test)]
mod tests {
    use super::*;
    use serde_json;

    #[test]
    fn test_config_deserialization() {
        let json = include_str!("../../test_data/account/preferences_config.json");

        let config: Config = serde_json::from_str(json).expect("Failed to deserialize");

        assert_eq!(config.language, Some("en-US".to_string()));

        assert!(config.prefs.is_some());
        let prefs = config.prefs.as_ref().unwrap();

        assert_eq!(prefs.dark, Some(true));
        assert_eq!(prefs.transp, Some(false));
        assert_eq!(
            prefs.bg_img,
            Some("https://lichess1.org/assets/lifat/background/gallery/bg03.webp".to_string())
        );
        assert_eq!(prefs.is_3d, Some(false));
        assert_eq!(prefs.theme, Some(Theme::Brown));
        assert_eq!(prefs.piece_set, Some(PieceSet::Cburnett));
        assert_eq!(prefs.theme_3d, Some(Theme3d::Woodi));
        assert_eq!(prefs.piece_set_3d, Some(PieceSet3d::Basic));
        assert_eq!(prefs.sound_set, Some(SoundSet::Standard));
        assert_eq!(prefs.auto_queen, Some(2));
        assert_eq!(prefs.auto_threefold, Some(3));
        assert_eq!(prefs.takeback, Some(3));
        assert_eq!(prefs.moretime, Some(3));
        assert_eq!(prefs.clock_tenths, Some(1));
        assert_eq!(prefs.clock_bar, Some(true));
        assert_eq!(prefs.clock_sound, Some(true));
        assert_eq!(prefs.premove, Some(true));
        assert_eq!(prefs.animation, Some(2));
        assert_eq!(prefs.piece_notation, Some(0));
        assert_eq!(prefs.captured, Some(true));
        assert_eq!(prefs.follow, Some(true));
        assert_eq!(prefs.highlight, Some(true));
        assert_eq!(prefs.destination, Some(true));
        assert_eq!(prefs.coords, Some(1));
        assert_eq!(prefs.replay, Some(2));
        assert_eq!(prefs.challenge, Some(4));
        assert_eq!(prefs.message, Some(3));
        assert_eq!(prefs.submit_move, Some(0));
        assert_eq!(prefs.confirm_resign, Some(1));
        assert_eq!(prefs.insight_share, Some(1));
        assert_eq!(prefs.keyboard_move, Some(0));
        assert_eq!(prefs.voice_move, Some(false));
        assert_eq!(prefs.zen, Some(0));
        assert_eq!(prefs.ratings, Some(1));
        assert_eq!(prefs.move_event, Some(2));
        assert_eq!(prefs.rook_castle, Some(1));
        assert_eq!(prefs.flairs, Some(true));
        assert_eq!(prefs.say_gg, Some(0));
    }
}
