use crate::model::*;

use serde::{Deserialize, Serialize};

#[derive(Eq, PartialEq, Clone, Debug)]
pub enum Package {
    Json(JsonValue),
    Command(Command),
    Binary(Vec<u8>),
    Error(u16, String),
}

#[derive(Eq, PartialEq, Clone, Debug)]
pub enum JsonValue {
    Null,
    True,
    False,
    Texture(Texture),
    TextureArray(Vec<Texture>),
}

#[derive(Serialize, Deserialize, Eq, PartialEq, Clone, Debug)]
pub enum Command {
    #[serde(rename = "ping")]
    Ping {},
    #[serde(rename = "pong")]
    Pong {},
    #[serde(rename = "query")]
    Query { query: Vec<String> },
    #[serde(rename = "get_texture")]
    GetTexture {
        id: Option<String>,
        name: Option<String>,
    },
    #[serde(rename = "get_texture_file")]
    GetTextureData { texture_hash: Sha256 },
    #[serde(rename = "get_texture_preview")]
    GetTexturePreview {
        texture_hash: Sha256,
        desired_format: TextureFormat,
    },
    #[serde(rename = "replace_texture")]
    ReplaceTexture {
        old: Option<Texture>,
        new: Option<Texture>,
    },
}

use super::error::*;

impl From<ProtocolError> for Package {
    fn from(item: ProtocolError) -> Self {
        match item {
            ProtocolError::BadRequest(msg) => Package::Error(400, msg),
            ProtocolError::FileNotFound(msg) => Package::Error(404, msg),
            ProtocolError::Conflict(msg) => Package::Error(409, msg),
            ProtocolError::InternalServerError(_err) => {
                Package::Error(500, "Internal Server Error.".to_string())
            }
            ProtocolError::NotImplemented => Package::Error(
                501,
                "Well, I'm sorry, \
                 but this feature is still a Todo :/"
                    .to_string(),
            ),
        }
    }
}

impl From<ProtocolResult<Vec<Texture>>> for Package {
    fn from(item: ProtocolResult<Vec<Texture>>) -> Self {
        match item {
            Ok(textures) => Package::Json(JsonValue::TextureArray(textures)),
            Err(err) => Package::from(err),
        }
    }
}

impl From<ProtocolResult<Option<Texture>>> for Package {
    fn from(item: ProtocolResult<Option<Texture>>) -> Self {
        match item {
            Ok(Some(texture)) => Package::Json(JsonValue::Texture(texture)),
            Ok(None) => Package::Json(JsonValue::Null),
            Err(err) => Package::from(err),
        }
    }
}

impl From<ProtocolResult<Vec<u8>>> for Package {
    fn from(item: ProtocolResult<Vec<u8>>) -> Self {
        match item {
            Ok(bin) => Package::Binary(bin),
            Err(err) => Package::from(err),
        }
    }
}
