#![deny(warnings)]
#![allow(dead_code)]
//! [TSM.ID].[11031972] -- Platform X Ecosystem
//! xcu-rpc -- Binary RPC Protocol (zero-copy, schema-driven)

use std::collections::HashMap;

#[derive(Debug)]
pub enum RpcError { MethodNotFound(String), DeserializeFailed(String), Timeout(String), Internal(String) }
impl std::fmt::Display for RpcError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self { Self::MethodNotFound(e) => write!(f, "Method: {e}"), Self::DeserializeFailed(e) => write!(f, "Deser: {e}"), Self::Timeout(e) => write!(f, "Timeout: {e}"), Self::Internal(e) => write!(f, "Internal: {e}") }
    }
}
impl std::error::Error for RpcError {}

#[derive(Debug, Clone)]
pub enum RpcValue { Null, Bool(bool), Int(i64), Float(f64), Str(String), Bytes(Vec<u8>), Array(Vec<RpcValue>), Map(Vec<(String, RpcValue)>) }

/// Binary frame: [magic(2)][version(1)][flags(1)][method_len(2)][payload_len(4)][method][payload]
#[derive(Debug, Clone)]
pub struct RpcFrame {
    pub request_id: u32,
    pub method: String,
    pub params: Vec<RpcValue>,
    pub is_response: bool,
    pub error: Option<String>,
}

const MAGIC: [u8; 2] = [0xC0, 0x01]; // XCU magic bytes

impl RpcFrame {
    pub fn request(id: u32, method: &str, params: Vec<RpcValue>) -> Self {
        Self { request_id: id, method: method.into(), params, is_response: false, error: None }
    }
    pub fn response(id: u32, result: Vec<RpcValue>) -> Self {
        Self { request_id: id, method: String::new(), params: result, is_response: true, error: None }
    }
    pub fn error_response(id: u32, err: &str) -> Self {
        Self { request_id: id, method: String::new(), params: Vec::new(), is_response: true, error: Some(err.into()) }
    }

    /// Serialize to binary frame
    pub fn encode(&self) -> Vec<u8> {
        let mut buf = Vec::with_capacity(64);
        buf.extend_from_slice(&[0xC0, 0x01]); // magic
        buf.push(1); // version
        buf.push(if self.is_response { 1 } else { 0 }); // flags
        buf.extend_from_slice(&self.request_id.to_be_bytes());
        let method_bytes = self.method.as_bytes();
        buf.extend_from_slice(&(method_bytes.len() as u16).to_be_bytes());
        buf.extend_from_slice(method_bytes);
        // Encode params count
        buf.extend_from_slice(&(self.params.len() as u16).to_be_bytes());
        for p in &self.params { Self::encode_value(&mut buf, p); }
        // Error field
        if let Some(ref err) = self.error {
            buf.push(1);
            let err_bytes = err.as_bytes();
            buf.extend_from_slice(&(err_bytes.len() as u16).to_be_bytes());
            buf.extend_from_slice(err_bytes);
        } else { buf.push(0); }
        buf
    }

    fn encode_value(buf: &mut Vec<u8>, val: &RpcValue) {
        match val {
            RpcValue::Null => buf.push(0),
            RpcValue::Bool(b) => { buf.push(1); buf.push(if *b { 1 } else { 0 }); }
            RpcValue::Int(n) => { buf.push(2); buf.extend_from_slice(&n.to_be_bytes()); }
            RpcValue::Float(n) => { buf.push(3); buf.extend_from_slice(&n.to_be_bytes()); }
            RpcValue::Str(s) => { buf.push(4); let b = s.as_bytes(); buf.extend_from_slice(&(b.len() as u32).to_be_bytes()); buf.extend_from_slice(b); }
            RpcValue::Bytes(b) => { buf.push(5); buf.extend_from_slice(&(b.len() as u32).to_be_bytes()); buf.extend_from_slice(b); }
            RpcValue::Array(arr) => { buf.push(6); buf.extend_from_slice(&(arr.len() as u16).to_be_bytes()); for v in arr { Self::encode_value(buf, v); } }
            RpcValue::Map(m) => { buf.push(7); buf.extend_from_slice(&(m.len() as u16).to_be_bytes()); for (k, v) in m { let kb = k.as_bytes(); buf.extend_from_slice(&(kb.len() as u16).to_be_bytes()); buf.extend_from_slice(kb); Self::encode_value(buf, v); } }
        }
    }

    /// Decode from binary
    pub fn decode(data: &[u8]) -> Result<Self, RpcError> {
        if data.len() < 10 { return Err(RpcError::DeserializeFailed("Too short".into())); }
        if data[0] != 0xC0 || data[1] != 0x01 { return Err(RpcError::DeserializeFailed("Bad magic".into())); }
        let is_response = data[3] == 1;
        let request_id = u32::from_be_bytes([data[4], data[5], data[6], data[7]]);
        let method_len = u16::from_be_bytes([data[8], data[9]]) as usize;
        let mut pos = 10;
        if pos + method_len > data.len() { return Err(RpcError::DeserializeFailed("Method truncated".into())); }
        let method = String::from_utf8_lossy(&data[pos..pos + method_len]).to_string();
        pos += method_len;
        // Params
        if pos + 2 > data.len() { return Err(RpcError::DeserializeFailed("No params count".into())); }
        let param_count = u16::from_be_bytes([data[pos], data[pos + 1]]) as usize;
        pos += 2;
        let mut params = Vec::with_capacity(param_count);
        for _ in 0..param_count {
            let (val, new_pos) = Self::decode_value(data, pos)?;
            params.push(val);
            pos = new_pos;
        }
        // Error
        let error = if pos < data.len() && data[pos] == 1 {
            pos += 1;
            if pos + 2 <= data.len() {
                let err_len = u16::from_be_bytes([data[pos], data[pos + 1]]) as usize;
                pos += 2;
                if pos + err_len <= data.len() { Some(String::from_utf8_lossy(&data[pos..pos + err_len]).to_string()) } else { None }
            } else { None }
        } else { None };

        Ok(Self { request_id, method, params, is_response, error })
    }

    fn decode_value(data: &[u8], pos: usize) -> Result<(RpcValue, usize), RpcError> {
        if pos >= data.len() { return Err(RpcError::DeserializeFailed("EOF".into())); }
        let tag = data[pos];
        let mut p = pos + 1;
        match tag {
            0 => Ok((RpcValue::Null, p)),
            1 => { if p >= data.len() { return Err(RpcError::DeserializeFailed("Bool".into())); } let v = data[p] != 0; Ok((RpcValue::Bool(v), p + 1)) }
            2 => { if p + 8 > data.len() { return Err(RpcError::DeserializeFailed("Int".into())); } let n = i64::from_be_bytes([data[p],data[p+1],data[p+2],data[p+3],data[p+4],data[p+5],data[p+6],data[p+7]]); Ok((RpcValue::Int(n), p + 8)) }
            3 => { if p + 8 > data.len() { return Err(RpcError::DeserializeFailed("Float".into())); } let n = f64::from_be_bytes([data[p],data[p+1],data[p+2],data[p+3],data[p+4],data[p+5],data[p+6],data[p+7]]); Ok((RpcValue::Float(n), p + 8)) }
            4 => { if p + 4 > data.len() { return Err(RpcError::DeserializeFailed("Str len".into())); } let len = u32::from_be_bytes([data[p],data[p+1],data[p+2],data[p+3]]) as usize; p += 4; if p + len > data.len() { return Err(RpcError::DeserializeFailed("Str".into())); } let s = String::from_utf8_lossy(&data[p..p+len]).to_string(); Ok((RpcValue::Str(s), p + len)) }
            5 => { if p + 4 > data.len() { return Err(RpcError::DeserializeFailed("Bytes len".into())); } let len = u32::from_be_bytes([data[p],data[p+1],data[p+2],data[p+3]]) as usize; p += 4; if p + len > data.len() { return Err(RpcError::DeserializeFailed("Bytes".into())); } Ok((RpcValue::Bytes(data[p..p+len].to_vec()), p + len)) }
            _ => Ok((RpcValue::Null, p)),
        }
    }
}

/// RPC Router: method → handler dispatch
pub struct RpcRouter {
    methods: HashMap<String, Box<dyn Fn(Vec<RpcValue>) -> Result<Vec<RpcValue>, RpcError> + Send + Sync>>,
}

impl RpcRouter {
    pub fn new() -> Self { Self { methods: HashMap::new() } }
    pub fn register<F>(&mut self, method: &str, handler: F) where F: Fn(Vec<RpcValue>) -> Result<Vec<RpcValue>, RpcError> + Send + Sync + 'static {
        self.methods.insert(method.into(), Box::new(handler));
    }
    pub fn dispatch(&self, frame: RpcFrame) -> RpcFrame {
        match self.methods.get(&frame.method) {
            Some(handler) => match handler(frame.params) {
                Ok(result) => RpcFrame::response(frame.request_id, result),
                Err(e) => RpcFrame::error_response(frame.request_id, &e.to_string()),
            },
            None => RpcFrame::error_response(frame.request_id, &format!("Method '{}' not found", frame.method)),
        }
    }
    pub fn method_count(&self) -> usize { self.methods.len() }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_encode_decode() {
        let frame = RpcFrame::request(42, "echo", vec![RpcValue::Str("hello".into()), RpcValue::Int(123)]);
        let encoded = frame.encode();
        let decoded = RpcFrame::decode(&encoded).unwrap();
        assert_eq!(decoded.request_id, 42);
        assert_eq!(decoded.method, "echo");
        assert_eq!(decoded.params.len(), 2);
    }
    #[test]
    fn test_router() {
        let mut router = RpcRouter::new();
        router.register("add", |params| {
            if let (Some(RpcValue::Int(a)), Some(RpcValue::Int(b))) = (params.get(0), params.get(1)) {
                Ok(vec![RpcValue::Int(a + b)])
            } else { Err(RpcError::Internal("Bad args".into())) }
        });
        let req = RpcFrame::request(1, "add", vec![RpcValue::Int(10), RpcValue::Int(20)]);
        let resp = router.dispatch(req);
        assert!(resp.is_response);
        if let Some(RpcValue::Int(n)) = resp.params.first() { assert_eq!(*n, 30); }
    }
    #[test]
    fn test_method_not_found() {
        let router = RpcRouter::new();
        let req = RpcFrame::request(1, "missing", vec![]);
        let resp = router.dispatch(req);
        assert!(resp.error.is_some());
    }
}
