use chrono::{DateTime, FixedOffset};
use std::convert::identity;

pub trait ToMd {
    fn to_md(&self) -> String;
}

#[derive(Debug)]
pub struct Doc<'src> {
    pub entries: Vec<Entry<'src>>,
}

impl<'src> Doc<'src> {
    // TODO: better parsing errors?
    pub fn new(f: &'src str) -> Option<Self> {
        let entries = f
            .split("\n## ")
            .map(|s| s.split_once("\n"))
            .skip(1)
            .filter_map(identity)
            .map(|(title, content)| (title.split_once(": "), content))
            .map(|(title, content)| {
                if let Some((ts, title)) = title {
                    Some(Entry {
                        timestamp: DateTime::parse_from_rfc3339(ts).unwrap(),
                        title,
                        content: content.trim_matches('\n'),
                    })
                } else {
                    None
                }
            })
            .collect::<Vec<_>>();

        entries.iter().all(|it| it.is_some()).then_some(Self {
            entries: entries.into_iter().filter_map(identity).collect(),
        })
    }
}

impl ToMd for Doc<'_> {
    fn to_md(&self) -> String {
        let mut r = "# Journal\n\n".to_owned();

        self.entries.iter().fold(r, |mut r, it| r + &it.to_md())
    }
}

#[derive(Debug, Clone)]
pub struct Entry<'src> {
    pub timestamp: DateTime<FixedOffset>,
    pub title: &'src str,
    pub content: &'src str,
}

impl ToMd for Entry<'_> {
    fn to_md(&self) -> String {
        format!(
            "## {}: {}\n\n{}\n\n",
            self.timestamp
                .fixed_offset()
                .to_rfc3339_opts(chrono::SecondsFormat::Secs, false),
            self.title,
            self.content
        )
    }
}
