// Copyright (c) 2024 Jason Witty <jasonpwitty+socktop@proton.me>.
// All rights reserved.
//
// Unit tests for terminado.rs module

use webterm::event::IO;
use webterm::terminado::TerminadoMessage;

// ============================================================================
// Serialization Tests
// ============================================================================

#[test]
fn test_serialize_resize() {
    let msg = TerminadoMessage::Resize { rows: 25, cols: 80 };
    let json = serde_json::to_string(&msg).unwrap();
    assert_eq!(json, r#"["set_size",25,80]"#);
}

#[test]
fn test_serialize_resize_large_dimensions() {
    let msg = TerminadoMessage::Resize {
        rows: 200,
        cols: 300,
    };
    let json = serde_json::to_string(&msg).unwrap();
    assert_eq!(json, r#"["set_size",200,300]"#);
}

#[test]
fn test_serialize_resize_minimum() {
    let msg = TerminadoMessage::Resize { rows: 1, cols: 1 };
    let json = serde_json::to_string(&msg).unwrap();
    assert_eq!(json, r#"["set_size",1,1]"#);
}

#[test]
fn test_serialize_stdin() {
    let msg = TerminadoMessage::Stdin(IO::from("hello world"));
    let json = serde_json::to_string(&msg).unwrap();
    assert_eq!(json, r#"["stdin","hello world"]"#);
}

#[test]
fn test_serialize_stdin_empty() {
    let msg = TerminadoMessage::Stdin(IO::from(""));
    let json = serde_json::to_string(&msg).unwrap();
    assert_eq!(json, r#"["stdin",""]"#);
}

#[test]
fn test_serialize_stdin_special_chars() {
    let msg = TerminadoMessage::Stdin(IO::from("tab\there\nnewline"));
    let json = serde_json::to_string(&msg).unwrap();
    assert_eq!(json, r#"["stdin","tab\there\nnewline"]"#);
}

#[test]
fn test_serialize_stdin_unicode() {
    let msg = TerminadoMessage::Stdin(IO::from("Hello 世界 🚀"));
    let json = serde_json::to_string(&msg).unwrap();
    assert_eq!(json, r#"["stdin","Hello 世界 🚀"]"#);
}

#[test]
fn test_serialize_stdout() {
    let msg = TerminadoMessage::Stdout(IO::from("output text"));
    let json = serde_json::to_string(&msg).unwrap();
    assert_eq!(json, r#"["stdout","output text"]"#);
}

#[test]
fn test_serialize_stdout_empty() {
    let msg = TerminadoMessage::Stdout(IO::from(""));
    let json = serde_json::to_string(&msg).unwrap();
    assert_eq!(json, r#"["stdout",""]"#);
}

#[test]
fn test_serialize_stdout_multiline() {
    let msg = TerminadoMessage::Stdout(IO::from("line1\nline2\nline3"));
    let json = serde_json::to_string(&msg).unwrap();
    assert_eq!(json, r#"["stdout","line1\nline2\nline3"]"#);
}

// ============================================================================
// Deserialization Tests
// ============================================================================

#[test]
fn test_deserialize_resize() {
    let json = r#"["set_size", 25, 80]"#;
    let msg = TerminadoMessage::from_json(json).expect("Failed to parse");
    assert_eq!(msg, TerminadoMessage::Resize { rows: 25, cols: 80 });
}

#[test]
fn test_deserialize_resize_no_spaces() {
    let json = r#"["set_size",25,80]"#;
    let msg = TerminadoMessage::from_json(json).expect("Failed to parse");
    assert_eq!(msg, TerminadoMessage::Resize { rows: 25, cols: 80 });
}

#[test]
fn test_deserialize_resize_large() {
    let json = r#"["set_size", 300, 500]"#;
    let msg = TerminadoMessage::from_json(json).expect("Failed to parse");
    assert_eq!(
        msg,
        TerminadoMessage::Resize {
            rows: 300,
            cols: 500
        }
    );
}

#[test]
fn test_deserialize_stdin() {
    let json = r#"["stdin", "hello world"]"#;
    let msg = TerminadoMessage::from_json(json).expect("Failed to parse");
    assert_eq!(msg, TerminadoMessage::Stdin(IO::from("hello world")));
}

#[test]
fn test_deserialize_stdin_empty() {
    let json = r#"["stdin", ""]"#;
    let msg = TerminadoMessage::from_json(json).expect("Failed to parse");
    assert_eq!(msg, TerminadoMessage::Stdin(IO::from("")));
}

#[test]
fn test_deserialize_stdin_special_chars() {
    let json = r#"["stdin", "tab\there\nnewline"]"#;
    let msg = TerminadoMessage::from_json(json).expect("Failed to parse");
    assert_eq!(msg, TerminadoMessage::Stdin(IO::from("tab\there\nnewline")));
}

#[test]
fn test_deserialize_stdin_unicode() {
    let json = r#"["stdin", "Hello 世界 🚀"]"#;
    let msg = TerminadoMessage::from_json(json).expect("Failed to parse");
    assert_eq!(msg, TerminadoMessage::Stdin(IO::from("Hello 世界 🚀")));
}

#[test]
fn test_deserialize_stdout() {
    let json = r#"["stdout", "output text"]"#;
    let msg = TerminadoMessage::from_json(json).expect("Failed to parse");
    assert_eq!(msg, TerminadoMessage::Stdout(IO::from("output text")));
}

#[test]
fn test_deserialize_stdout_empty() {
    let json = r#"["stdout", ""]"#;
    let msg = TerminadoMessage::from_json(json).expect("Failed to parse");
    assert_eq!(msg, TerminadoMessage::Stdout(IO::from("")));
}

// ============================================================================
// Round-trip Tests (Serialize then Deserialize)
// ============================================================================

#[test]
fn test_roundtrip_resize() {
    let original = TerminadoMessage::Resize {
        rows: 40,
        cols: 120,
    };
    let json = serde_json::to_string(&original).unwrap();
    let parsed = TerminadoMessage::from_json(&json).expect("Failed to parse");
    assert_eq!(original, parsed);
}

#[test]
fn test_roundtrip_stdin() {
    let original = TerminadoMessage::Stdin(IO::from("test input"));
    let json = serde_json::to_string(&original).unwrap();
    let parsed = TerminadoMessage::from_json(&json).expect("Failed to parse");
    assert_eq!(original, parsed);
}

#[test]
fn test_roundtrip_stdout() {
    let original = TerminadoMessage::Stdout(IO::from("test output"));
    let json = serde_json::to_string(&original).unwrap();
    let parsed = TerminadoMessage::from_json(&json).expect("Failed to parse");
    assert_eq!(original, parsed);
}

// ============================================================================
// Error Cases
// ============================================================================

#[test]
fn test_deserialize_invalid_json() {
    let json = r#"not valid json"#;
    let result = TerminadoMessage::from_json(json);
    assert!(result.is_err());
}

#[test]
fn test_deserialize_not_array() {
    let json = r#"{"type": "stdin", "data": "test"}"#;
    let result = TerminadoMessage::from_json(json);
    assert!(result.is_err());
}

#[test]
fn test_deserialize_empty_array() {
    let json = r#"[]"#;
    let result = TerminadoMessage::from_json(json);
    assert!(result.is_err());
}

#[test]
fn test_deserialize_unknown_type() {
    let json = r#"["unknown_type", "data"]"#;
    let result = TerminadoMessage::from_json(json);
    assert!(result.is_err());
}

#[test]
fn test_deserialize_stdin_wrong_length() {
    let json = r#"["stdin"]"#;
    let result = TerminadoMessage::from_json(json);
    assert!(result.is_err());
}

#[test]
fn test_deserialize_stdin_too_many_elements() {
    let json = r#"["stdin", "data", "extra"]"#;
    let result = TerminadoMessage::from_json(json);
    assert!(result.is_err());
}

#[test]
fn test_deserialize_stdout_wrong_length() {
    let json = r#"["stdout"]"#;
    let result = TerminadoMessage::from_json(json);
    assert!(result.is_err());
}

#[test]
fn test_deserialize_resize_wrong_length() {
    let json = r#"["set_size", 25]"#;
    let result = TerminadoMessage::from_json(json);
    assert!(result.is_err());
}

#[test]
fn test_deserialize_resize_missing_rows() {
    let json = r#"["set_size"]"#;
    let result = TerminadoMessage::from_json(json);
    assert!(result.is_err());
}

#[test]
fn test_deserialize_resize_non_integer() {
    let json = r#"["set_size", "25", "80"]"#;
    let result = TerminadoMessage::from_json(json);
    assert!(result.is_err());
}

#[test]
fn test_deserialize_stdin_non_string() {
    let json = r#"["stdin", 123]"#;
    let result = TerminadoMessage::from_json(json);
    assert!(result.is_err());
}

#[test]
fn test_deserialize_type_not_string() {
    let json = r#"[123, "data"]"#;
    let result = TerminadoMessage::from_json(json);
    assert!(result.is_err());
}

// ============================================================================
// Edge Cases
// ============================================================================

#[test]
fn test_message_equality() {
    let msg1 = TerminadoMessage::Stdin(IO::from("same"));
    let msg2 = TerminadoMessage::Stdin(IO::from("same"));
    let msg3 = TerminadoMessage::Stdin(IO::from("different"));

    assert_eq!(msg1, msg2);
    assert_ne!(msg1, msg3);
}

#[test]
fn test_message_clone() {
    let original = TerminadoMessage::Resize { rows: 30, cols: 90 };
    let cloned = original.clone();
    assert_eq!(original, cloned);
}

#[test]
fn test_resize_different_values() {
    let msg1 = TerminadoMessage::Resize { rows: 25, cols: 80 };
    let msg2 = TerminadoMessage::Resize { rows: 30, cols: 90 };
    assert_ne!(msg1, msg2);
}

#[test]
fn test_different_message_types_not_equal() {
    let stdin = TerminadoMessage::Stdin(IO::from("test"));
    let stdout = TerminadoMessage::Stdout(IO::from("test"));
    assert_ne!(stdin, stdout);
}
