use serde::{Deserialize, Serialize};
use crate::ids::SurfaceId;

/// Split orientation. `H` lays children left-to-right; `V` top-to-bottom.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Orient {
    H,
    V,
}

/// Recursive n-ary layout tree. Externally tagged so JSON reads
/// `{ "leaf": { "surface_id": "s_1" } }` / `{ "split": { ... } }`.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum LayoutNode {
    Leaf { surface_id: SurfaceId },
    Split {
        orient: Orient,
        ratios: Vec<f32>,
        children: Vec<LayoutNode>,
    },
}

impl LayoutNode {
    pub fn leaf(id: SurfaceId) -> Self {
        LayoutNode::Leaf { surface_id: id }
    }
}

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

    #[test]
    fn leaf_serializes_externally_tagged() {
        let n = LayoutNode::leaf(SurfaceId("s_1".into()));
        let j = serde_json::to_string(&n).unwrap();
        assert_eq!(j, r#"{"leaf":{"surface_id":"s_1"}}"#);
    }

    #[test]
    fn split_round_trips() {
        let n = LayoutNode::Split {
            orient: Orient::V,
            ratios: vec![0.5, 0.5],
            children: vec![
                LayoutNode::leaf(SurfaceId("s_1".into())),
                LayoutNode::leaf(SurfaceId("s_2".into())),
            ],
        };
        let j = serde_json::to_string(&n).unwrap();
        assert!(j.contains(r#""split""#));
        assert!(j.contains(r#""orient":"v""#));
        let back: LayoutNode = serde_json::from_str(&j).unwrap();
        assert_eq!(back, n);
    }
}
