use std::fmt;
use busylib::model::smart_home::{
PairingStatus, SmartHomePairingInfo, SmartHomePairingPayload, SmartHomeSwitchState,
SwitchStartup,
};
use serde::Serialize;
use crate::reporter::events::CliEvent;
use crate::reporter::events::fields::{field, write_fields};
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub struct SmartHomePairingEvent(SmartHomePairingInfo);
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub struct SmartHomeStartPairingEvent(SmartHomePairingPayload);
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub struct SmartHomeSwitchEvent(SmartHomeSwitchState);
impl SmartHomePairingEvent {
pub fn new(pairing: SmartHomePairingInfo) -> Self {
Self(pairing)
}
}
impl SmartHomeStartPairingEvent {
pub fn new(payload: SmartHomePairingPayload) -> Self {
Self(payload)
}
}
impl SmartHomeSwitchEvent {
pub fn new(switch: SmartHomeSwitchState) -> Self {
Self(switch)
}
}
impl From<SmartHomePairingEvent> for CliEvent {
fn from(event: SmartHomePairingEvent) -> Self {
CliEvent::SmartHomePairing(event)
}
}
impl From<SmartHomeStartPairingEvent> for CliEvent {
fn from(event: SmartHomeStartPairingEvent) -> Self {
CliEvent::SmartHomeStartPairing(event)
}
}
impl From<SmartHomeSwitchEvent> for CliEvent {
fn from(event: SmartHomeSwitchEvent) -> Self {
CliEvent::SmartHomeSwitch(event)
}
}
impl fmt::Display for SmartHomePairingEvent {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let pairing = &self.0;
let mut fields = Vec::new();
if let Some(fabric_count) = pairing.fabric_count {
fields.push(field("fabric count", fabric_count));
}
if let Some(latest) = &pairing.latest_pairing_status {
fields.push(field("latest status", pairing_status_label(&latest.value)));
if let Some(timestamp) = latest.timestamp {
fields.push(field("latest status timestamp", timestamp));
}
}
write_fields(f, &fields)
}
}
impl fmt::Display for SmartHomeStartPairingEvent {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let payload = &self.0;
let mut fields = Vec::new();
if let Some(available_until) = payload.available_until {
fields.push(field("available until", available_until));
}
if let Some(qr_code) = &payload.qr_code {
fields.push(field("qr code", qr_code));
}
if let Some(manual_code) = &payload.manual_code {
fields.push(field("manual code", manual_code));
}
write_fields(f, &fields)
}
}
impl fmt::Display for SmartHomeSwitchEvent {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let switch = &self.0;
let mut fields = Vec::new();
if let Some(state) = switch.state {
fields.push(field("state", if state { "on" } else { "off" }));
}
if let Some(startup) = switch.startup {
fields.push(field("startup", switch_startup_label(startup)));
}
write_fields(f, &fields)
}
}
fn pairing_status_label(status: &PairingStatus) -> &str {
match status {
PairingStatus::NeverStarted => "never_started",
PairingStatus::Started => "started",
PairingStatus::CompletedSuccessfully => "completed_successfully",
PairingStatus::Failed => "failed",
PairingStatus::Unknown(status) => status,
}
}
fn switch_startup_label(startup: SwitchStartup) -> &'static str {
match startup {
SwitchStartup::Off => "off",
SwitchStartup::On => "on",
SwitchStartup::Toggle => "toggle",
SwitchStartup::Last => "last",
}
}
#[cfg(test)]
mod tests {
use busylib::model::smart_home::PairingStatusInfo;
use serde_json::json;
use super::*;
#[test]
fn renders_the_pairing_status_without_a_timestamp() {
let event = SmartHomePairingEvent::new(SmartHomePairingInfo {
fabric_count: Some(0),
latest_pairing_status: Some(PairingStatusInfo {
value: PairingStatus::NeverStarted,
timestamp: None,
}),
});
assert_eq!(
event.to_string(),
"fabric count: 0\nlatest status: never_started"
);
}
#[test]
fn renders_the_switch_state_as_on_or_off() {
let on = SmartHomeSwitchEvent::new(SmartHomeSwitchState::on());
let off = SmartHomeSwitchEvent::new(SmartHomeSwitchState::off());
assert_eq!(on.to_string(), "state: on");
assert_eq!(off.to_string(), "state: off");
assert_eq!(
serde_json::to_value(CliEvent::from(off)).unwrap(),
json!({"event": "smart_home_switch", "state": false})
);
}
#[test]
fn renders_the_pairing_payload() {
let event = SmartHomeStartPairingEvent::new(SmartHomePairingPayload {
available_until: Some(1761582532251),
qr_code: Some("MT:Y.K90".to_string()),
manual_code: Some("34970112332".to_string()),
});
assert_eq!(
event.to_string(),
"available until: 1761582532251\nqr code: MT:Y.K90\nmanual code: 34970112332"
);
}
}