use crate::entities::{Duration, Error, Result, RunningWork, Scheme, Work};
use serde::{Deserialize, Serialize};

#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub(crate) struct Job {
    pub(crate) worker: String,
    pub(crate) client: String,
    pub(crate) subject: String,
    pub(crate) running: Option<RunningWork>,
    pub(crate) work: Vec<Work>,
    pub(crate) scheme: Option<Scheme>,
    pub(crate) deleted: bool,
}

impl Job {
    #[cfg(test)]
    pub(crate) fn new(
        worker: String,
        client: String,
        subject: String,
        scheme: Option<Scheme>,
    ) -> Self {
        Self {
            worker,
            client,
            subject,
            scheme,
            ..Default::default()
        }
    }

    pub(crate) fn hours(&self, job_id: usize) -> Result<f64> {
        Ok(self.work(job_id)?.num_minutes() as f64 / 60.0)
    }

    pub(crate) fn work(&self, job_id: usize) -> Result<Duration> {
        Ok(self
            .scheme(job_id)?
            .measure_work(self.work.iter().map(|work| &work.work_time))
            + if let Some(current_work) = &self.running {
                current_work.duration()
            } else {
                Duration::zero()
            })
    }

    pub(crate) fn scheme(&self, job_id: usize) -> Result<&Scheme> {
        if let Some(scheme) = &self.scheme {
            Ok(scheme)
        } else {
            Err(Error::JobMissingScheme(job_id))
        }
    }
}
