use chrono::TimeZone;
use serde::Serialize;
use crate::tapo_vendor::error::Error;
use crate::tapo_vendor::requests::EnergyDataInterval;
use crate::tapo_vendor::utils::{local_day, local_midnight};
#[derive(Debug, Default, Serialize)]
pub(crate) struct GetEnergyDataParams {
start_timestamp: u64,
end_timestamp: u64,
interval: u64,
}
impl GetEnergyDataParams {
pub fn new<Tz: TimeZone>(interval: EnergyDataInterval, timezone: &Tz) -> Result<Self, Error> {
let params = match interval {
EnergyDataInterval::Hourly {
start_date,
end_date,
} => {
let (start, _) = local_day(start_date, timezone)?;
let (_, end) = local_day(end_date, timezone)?;
Self {
start_timestamp: start.timestamp() as u64,
end_timestamp: end.timestamp() as u64,
interval: 60,
}
}
EnergyDataInterval::Daily { start_date } => {
let timestamp = local_midnight(start_date, timezone).timestamp() as u64;
Self {
start_timestamp: timestamp,
end_timestamp: timestamp,
interval: 1440,
}
}
EnergyDataInterval::Monthly { start_date } => {
let timestamp = local_midnight(start_date, timezone).timestamp() as u64;
Self {
start_timestamp: timestamp,
end_timestamp: timestamp,
interval: 43200,
}
}
};
Ok(params)
}
}
#[cfg(test)]
mod tests {
use chrono::{NaiveDate, NaiveTime, Utc};
use chrono_tz::America::Santiago;
use super::*;
#[test]
fn test_hourly_covers_whole_days_across_dst_changes() {
for (date, hours) in [((2026, 9, 6), 23), ((2026, 4, 4), 25)] {
let date = NaiveDate::from_ymd_opt(date.0, date.1, date.2).unwrap();
let params = GetEnergyDataParams::new(
EnergyDataInterval::Hourly {
start_date: date,
end_date: date,
},
&Santiago,
)
.unwrap();
assert_eq!(
params.end_timestamp - params.start_timestamp,
hours * 3600 - 1
);
}
}
#[test]
fn test_daily_with_skipped_midnight_starts_when_clocks_resume() {
let date = NaiveDate::from_ymd_opt(2026, 9, 6).unwrap();
let params =
GetEnergyDataParams::new(EnergyDataInterval::Daily { start_date: date }, &Santiago)
.unwrap();
let expected = date
.and_time(NaiveTime::MIN)
.and_local_timezone(Utc)
.unwrap()
.timestamp()
+ 4 * 3600;
assert_eq!(params.start_timestamp, expected as u64);
}
}