use super::{Day, Goal, TimeFilter};
use crate::models::budget::Budget;
use crate::models::repetition::Repetition;
use chrono::NaiveDateTime;
use log::info;
use serde::{Deserialize, Deserializer};
impl From<String> for Day {
    fn from(day: String) -> Self {
        info!("From<String> day-string: {:?}", day);
        match day.to_lowercase().as_str() {
            "fri" => Day::Fri,
            "sat" => Day::Sat,
            "sun" => Day::Sun,
            "mon" => Day::Mon,
            "tue" => Day::Tue,
            "wed" => Day::Wed,
            "thu" => Day::Thu,
            _ => panic!("Invalid day selection"),
        }
    }
}
impl From<Day> for String {
    fn from(day: Day) -> Self {
        info!("From<Days> day: {:?}", day);
        match day {
            Day::Fri => "Fri".into(),
            Day::Sat => "Sat".into(),
            Day::Sun => "Sun".into(),
            Day::Mon => "Mon".into(),
            Day::Tue => "Tue".into(),
            Day::Wed => "Wed".into(),
            Day::Thu => "Thu".into(),
        }
    }
}
impl Goal {
    pub fn new(id: usize) -> Self {
        Self {
            id: id.to_string(),
            title: String::from("Test"),
            ..Default::default()
        }
    }
    pub fn title(mut self, title: &str) -> Self {
        self.title = title.to_string();
        self
    }
    pub fn duration(mut self, min_duration: usize) -> Self {
        self.min_duration = Some(min_duration);
        self
    }
    pub fn repeat(mut self, repetition: Repetition) -> Self {
        self.repeat = Some(repetition);
        self
    }
    pub fn start(mut self, start: NaiveDateTime) -> Self {
        self.start = Some(start);
        self
    }
    pub fn deadline(mut self, deadline: NaiveDateTime) -> Self {
        self.deadline = Some(deadline);
        self
    }
    pub fn deserialize_budget_vec<'de, D>(deserializer: D) -> Result<Option<Vec<Budget>>, D::Error>
    where
        D: Deserializer<'de>,
    {
        let s: Option<Vec<Budget>> = Option::deserialize(deserializer)?;
        if let Some(s) = s {
            if !s.is_empty() {
                return Ok(Some(s));
            }
        }
        Ok(None)
    }
}
impl std::fmt::Display for TimeFilter {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "TimeFilter [ after_time: {:?}, before_time: {:?}, on_days: {:?}, not_on: {:?} ]",
            self.after_time, self.before_time, self.on_days, self.not_on
        )
    }
}
#[cfg(test)]
mod tests {
    mod serializing_deserializing {
        use crate::models::budget::Budget;
        use crate::models::budget::BudgetType::Weekly;
        use crate::models::goal::Goal;
        #[test]
        fn deserializing_of_empty_budgetlist_produces_none() {
            let goal_deserialized: Goal = serde_json::from_str(
                r#"{    
                  "id": "1",
                  "title": "testing new api",
                  "budgets": []
                  }"#,
            )
            .unwrap();
            assert_eq!(goal_deserialized.budgets, None);
        }
        #[test]
        fn deserializing_of_non_empty_budgetlist_produces_correct_budgetlist() {
            let goal_deserialized: Goal = serde_json::from_str(
                r#"{    
                  "id": "1",
                  "title": "testing new api",
                  "budgets": [{
                    "budget_type": "Weekly",
                    "min": 40
                    }]
                  }"#,
            )
            .unwrap();
            assert_eq!(
                goal_deserialized.budgets,
                Some(vec![Budget {
                    budget_type: Weekly,
                    min: Some(40),
                    max: None
                }])
            );
        }
        #[test]
        fn extra_fields_are_ignored() {
            let _: Goal = serde_json::from_str(
                r#"{    
                  "id": "1",
                  "title": "testing new api",
                  "created_at": "2023-09-03T10:38:35.505Z"
                  }"#,
            )
            .unwrap();
        }
    }
}