//! DevicePlugin 集成测试
//!
//! 测试 DeviceCommand/DeviceResponse/DeviceEvent 的序列化以及 MockBackend 的行为。

use crate::core::message::{
    DeviceCapability, DeviceCommand, DeviceEvent, DeviceResponse, PixelFormat, SensorType,
    TouchAction,
};
use crate::plugins::device::backend::DeviceBackend;
use anyhow::Result;

/// MockBackend — 用于测试的模拟设备后端
///
/// 不依赖真实硬件，返回预定义的响应数据。
struct MockBackend {
    initialized: bool,
}

impl MockBackend {
    fn new() -> Self {
        Self { initialized: false }
    }
}

impl DeviceBackend for MockBackend {
    fn name(&self) -> &str {
        "mock"
    }

    fn init(&mut self, _config: &serde_json::Value) -> Result<()> {
        self.initialized = true;
        Ok(())
    }

    fn capabilities(&self) -> Vec<DeviceCapability> {
        vec![
            DeviceCapability::Display,
            DeviceCapability::Backlight,
            DeviceCapability::Cursor,
        ]
    }

    fn handle_command(&mut self, cmd: DeviceCommand) -> Result<DeviceResponse> {
        match cmd {
            DeviceCommand::GetDisplayInfo => Ok(DeviceResponse::DisplayInfo {
                width: 1280,
                height: 800,
                format: PixelFormat::RGB888,
            }),
            DeviceCommand::SetSleepInhibit(_) => Ok(DeviceResponse::Ok),
            DeviceCommand::SetBacklight(_) => Ok(DeviceResponse::Ok),
            DeviceCommand::SetCursorVisible(_) => Ok(DeviceResponse::Ok),
            _ => Ok(DeviceResponse::Error("not supported".to_string())),
        }
    }

    fn shutdown(&mut self) -> Result<()> {
        self.initialized = false;
        Ok(())
    }
}

// ── 序列化测试 ──

#[test]
fn test_device_command_serialization() {
    let commands = vec![
        DeviceCommand::GetDisplayInfo,
        DeviceCommand::SetBrightness(75),
        DeviceCommand::SetBacklight(true),
        DeviceCommand::WriteFramebuffer {
            data: vec![0xFF, 0x00, 0xFF],
            format: PixelFormat::RGB888,
        },
        DeviceCommand::SetSleepInhibit(true),
        DeviceCommand::GetBatteryLevel,
        DeviceCommand::SetVolume(50),
        DeviceCommand::PlayAudio {
            path: "/audio/test.wav".to_string(),
        },
        DeviceCommand::GetTouchEvents,
        DeviceCommand::GetButtonState,
        DeviceCommand::GetSensorData(SensorType::Temperature),
        DeviceCommand::CustomCommand {
            subsystem: "gpio".to_string(),
            payload: serde_json::json!({"pin": 17, "value": 1}),
        },
    ];

    for cmd in commands {
        let json = serde_json::to_string(&cmd).expect("DeviceCommand should serialize");
        let decoded: DeviceCommand =
            serde_json::from_str(&json).expect("DeviceCommand should deserialize");
        let json2 = serde_json::to_string(&decoded).expect("decoded should serialize again");
        assert_eq!(json, json2, "DeviceCommand round trip should be stable");
    }
}

#[test]
fn test_device_response_serialization() {
    let responses = vec![
        DeviceResponse::DisplayInfo {
            width: 1920,
            height: 1080,
            format: PixelFormat::RGBA8888,
        },
        DeviceResponse::SensorData {
            sensor: SensorType::Temperature,
            value: 23.5,
        },
        DeviceResponse::BatteryLevel(85),
        DeviceResponse::Ok,
        DeviceResponse::Error("device not found".to_string()),
        DeviceResponse::Custom(serde_json::json!({"status": "ready"})),
    ];

    for resp in responses {
        let json = serde_json::to_string(&resp).expect("DeviceResponse should serialize");
        let decoded: DeviceResponse =
            serde_json::from_str(&json).expect("DeviceResponse should deserialize");
        let json2 = serde_json::to_string(&decoded).expect("decoded should serialize again");
        assert_eq!(json, json2, "DeviceResponse round trip should be stable");
    }
}

#[test]
fn test_device_event_serialization() {
    let events = vec![
        DeviceEvent::TouchEvent {
            x: 100,
            y: 200,
            action: TouchAction::Down,
        },
        DeviceEvent::ButtonEvent {
            button: 1,
            pressed: true,
        },
        DeviceEvent::BatteryLow(15),
        DeviceEvent::DisplayConnected,
        DeviceEvent::DisplayDisconnected,
        DeviceEvent::SensorAlert {
            sensor: SensorType::Temperature,
            value: 85.0,
        },
    ];

    for event in events {
        let json = serde_json::to_string(&event).expect("DeviceEvent should serialize");
        let decoded: DeviceEvent =
            serde_json::from_str(&json).expect("DeviceEvent should deserialize");
        let json2 = serde_json::to_string(&decoded).expect("decoded should serialize again");
        assert_eq!(json, json2, "DeviceEvent round trip should be stable");
    }
}

// ── MockBackend 行为测试 ──

#[test]
fn test_mock_backend_capabilities() {
    let backend = MockBackend::new();
    let caps = backend.capabilities();
    assert_eq!(caps.len(), 3);
    assert!(caps.contains(&DeviceCapability::Display));
    assert!(caps.contains(&DeviceCapability::Backlight));
    assert!(caps.contains(&DeviceCapability::Cursor));
}

#[test]
fn test_mock_backend_get_display_info() {
    let mut backend = MockBackend::new();
    backend
        .init(&serde_json::json!({}))
        .expect("init should succeed");

    let response = backend
        .handle_command(DeviceCommand::GetDisplayInfo)
        .expect("GetDisplayInfo should succeed");

    match response {
        DeviceResponse::DisplayInfo {
            width,
            height,
            format,
        } => {
            assert_eq!(width, 1280);
            assert_eq!(height, 800);
            assert!(matches!(format, PixelFormat::RGB888));
        }
        _ => panic!("expected DisplayInfo response"),
    }
}

#[test]
fn test_mock_backend_set_sleep_inhibit() {
    let mut backend = MockBackend::new();
    backend
        .init(&serde_json::json!({}))
        .expect("init should succeed");

    let response = backend
        .handle_command(DeviceCommand::SetSleepInhibit(true))
        .expect("SetSleepInhibit should succeed");

    assert!(matches!(response, DeviceResponse::Ok));
}

#[test]
fn test_mock_backend_unsupported_command() {
    let mut backend = MockBackend::new();
    backend
        .init(&serde_json::json!({}))
        .expect("init should succeed");

    let response = backend
        .handle_command(DeviceCommand::GetBatteryLevel)
        .expect("unsupported command should return Error response");

    match response {
        DeviceResponse::Error(msg) => {
            assert_eq!(msg, "not supported");
        }
        _ => panic!("expected Error response for unsupported command"),
    }
}

#[test]
fn test_mock_backend_set_cursor_visible() {
    let mut backend = MockBackend::new();
    backend
        .init(&serde_json::json!({}))
        .expect("init should succeed");

    let response_hide = backend
        .handle_command(DeviceCommand::SetCursorVisible(false))
        .expect("SetCursorVisible(false) should succeed");
    assert!(matches!(response_hide, DeviceResponse::Ok));

    let response_show = backend
        .handle_command(DeviceCommand::SetCursorVisible(true))
        .expect("SetCursorVisible(true) should succeed");
    assert!(matches!(response_show, DeviceResponse::Ok));
}

#[test]
fn test_mock_backend_cursor_capability() {
    let backend = MockBackend::new();
    let caps = backend.capabilities();
    assert!(
        caps.contains(&DeviceCapability::Cursor),
        "MockBackend should declare Cursor capability"
    );
}

#[test]
fn test_device_command_cursor_serialization() {
    let commands = vec![
        DeviceCommand::SetCursorVisible(true),
        DeviceCommand::SetCursorVisible(false),
    ];

    for cmd in commands {
        let json = serde_json::to_string(&cmd).expect("SetCursorVisible should serialize");
        let decoded: DeviceCommand =
            serde_json::from_str(&json).expect("SetCursorVisible should deserialize");
        let json2 = serde_json::to_string(&decoded).expect("decoded should serialize again");
        assert_eq!(json, json2, "SetCursorVisible round trip should be stable");
    }
}

#[test]
fn test_device_capability_cursor() {
    let cap = DeviceCapability::Cursor;
    let json = serde_json::to_string(&cap).expect("DeviceCapability::Cursor should serialize");
    let decoded: DeviceCapability =
        serde_json::from_str(&json).expect("DeviceCapability::Cursor should deserialize");
    let json2 = serde_json::to_string(&decoded).expect("decoded should serialize again");
    assert_eq!(
        json, json2,
        "DeviceCapability::Cursor round trip should be stable"
    );
}
