use bytes::Bytes;
use lanspread_db::db::{Game, GameFileDescription};
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
pub enum Request {
    Ping,
    ListGames,
    GetGame {
        id: String,
    },
    GetGameFileData(GameFileDescription),
    GetGameFileChunk {
        game_id: String,
        relative_path: String,
        offset: u64,
        length: u64,
    },
    AnnounceGames(Vec<Game>),
    Invalid(Bytes, String),
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum Response {
    Pong,
    ListGames(Vec<Game>),
    GetGame {
        id: String,
        file_descriptions: Vec<GameFileDescription>,
    },
    GameNotFound(String),
    InvalidRequest(Bytes, String),
    EncodingError(String),
    DecodingError(Bytes, String),
    InternalPeerError(String),
}

// Add Message trait
pub trait Message {
    fn decode(bytes: Bytes) -> Self;
    fn encode(&self) -> Bytes;
}

// Implement for Request
impl Message for Request {
    fn decode(bytes: Bytes) -> Self {
        match serde_json::from_slice(&bytes) {
            Ok(t) => t,
            Err(e) => {
                tracing::error!(?e, "Request decoding error");
                Request::Invalid(bytes, e.to_string())
            }
        }
    }

    fn encode(&self) -> Bytes {
        match serde_json::to_vec(self) {
            Ok(s) => Bytes::from(s),
            Err(e) => {
                tracing::error!(?e, "Request encoding error");
                Bytes::from(format!(r#"{{"error": "encoding error: {e}"}}"#))
            }
        }
    }
}

// Implement for Response
impl Message for Response {
    fn decode(bytes: Bytes) -> Self {
        match serde_json::from_slice(&bytes) {
            Ok(t) => t,
            Err(e) => {
                tracing::error!(?e, "Response decoding error");
                Response::DecodingError(bytes, e.to_string())
            }
        }
    }

    fn encode(&self) -> Bytes {
        match serde_json::to_vec(self) {
            Ok(s) => Bytes::from(s),
            Err(e) => {
                tracing::error!(?e, "Response encoding error");
                Bytes::from(format!(r#"{{"error": "encoding error: {e}"}}"#))
            }
        }
    }
}
