// use git_next_core::git::graph::Log; use lazy_static::lazy_static; use ratatui::{ style::{Color, Style, Styled as _}, text::{Line, Span, Text}, widgets::{Paragraph, Widget}, }; use regex::Regex; use tracing::info; use super::HeightContraintLength; pub struct CommitLog<'a> { pub log: &'a Log, } impl<'a> HeightContraintLength for CommitLog<'a> { fn height_constraint_length(&self) -> u16 { u16::try_from(self.log.len()).unwrap_or(u16::MAX) } } impl<'a> Widget for CommitLog<'a> { fn render(self, area: ratatui::prelude::Rect, buf: &mut ratatui::prelude::Buffer) where Self: Sized, { Paragraph::new(Text::from( self.log .iter() .map(LogLine::new) .map(Line::from) .collect::>(), )) .render(area, buf); } } struct LogLine { raw: String, } impl LogLine { fn new(raw: impl Into) -> Self { Self { raw: raw.into() } } } lazy_static::lazy_static! { static ref RE: Regex = #[allow(clippy::unwrap_used)] Regex::new( r"^(?
.*)\s(?[0-9a-f]{7})\s\((?.*?)\)\s(?.*)",
        ).unwrap();

    static ref BRANCHES: Regex =
    #[allow(clippy::unwrap_used)]
        Regex::new(
            r"origin\/(?[^,]+)",
        ).unwrap();
}
impl From for Line<'_> {
    fn from(value: LogLine) -> Self {
        if let Some(caps) = RE.captures(&value.raw) {
            let pre = caps["pre"].to_owned();
            let hash = caps["hash"].to_owned();
            let message = caps["message"].to_owned();
            info!(branches=?caps["branches"], "raw branches");
            let mut branches = BRANCHES
                .captures_iter(&caps["branches"])
                .map(|captures| captures["branch"].to_owned())
                .collect::>();
            if branches.is_empty() {
                // line without branches
                Line::from(vec![
                    pre.into(),
                    " ".into(),
                    hash.into(),
                    " ".into(),
                    message.into(),
                ])
            } else {
                // line withbranches
                let mut spans = vec![pre.into(), " ".into(), hash.into(), " ".into()];
                info!(?branches, "matched branch list");
                branches.sort();
                branches
                    .into_iter()
                    .map(|branch| Span::from(branch).style(Style::default().fg(Color::Blue)))
                    .for_each(|span| {
                        spans.push("[".into());
                        spans.push(span);
                        spans.push("]".into());
                    });
                spans.push(" ".into());
                spans.push(message.into());
                Line::from(spans)
            }
        } else {
            // non-commit line
            Line::from(value.raw.clone())
        }
    }
}

#[cfg(test)]
mod tests {
    use tracing::info;

    use super::RE;

    #[test_log::test]
    fn parse_log_line() -> Result<(), Box> {
        let line = "* 97b6853 (origin/next, origin/main, origin/dev, origin/HEAD) refactor(tui): simplify repo identity widget";
        RE.captures(line).map_or_else(
            || Err("Failed to capture".into()),
            |caps| {
                info!(?caps, "");
                assert_eq!(&caps["pre"], "*");
                assert_eq!(&caps["hash"], "97b6853");
                assert_eq!(
                    &caps["branches"],
                    "origin/next, origin/main, origin/dev, origin/HEAD"
                );
                assert_eq!(
                    &caps["message"],
                    "refactor(tui): simplify repo identity widget"
                );
                Ok(())
            },
        )
    }
}