use crate::analyser::BumpType;
use crate::error::{BumperError, BumperResult};
use std::fmt;

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Version {
    pub major: u32,
    pub minor: u32,
    pub patch: u32,
}

impl fmt::Display for Version {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}.{}.{}", self.major, self.minor, self.patch)
    }
}

impl Version {
    pub fn parse(version_str: &str) -> BumperResult<Self> {
        let parts: Vec<&str> = version_str.split('.').collect();

        if parts.len() != 3 {
            return Err(BumperError::InvalidVersion(version_str.to_string()));
        }

        let major = parts[0]
            .parse::<u32>()
            .map_err(|_| BumperError::InvalidVersion(version_str.to_string()))?;
        let minor = parts[1]
            .parse::<u32>()
            .map_err(|_| BumperError::InvalidVersion(version_str.to_string()))?;
        let patch = parts[2]
            .parse::<u32>()
            .map_err(|_| BumperError::InvalidVersion(version_str.to_string()))?;

        Ok(Version {
            major,
            minor,
            patch,
        })
    }

    pub fn bump(&self, bump_type: BumpType) -> Self {
        match bump_type {
            BumpType::Major => Version {
                major: self.major + 1,
                minor: 0,
                patch: 0,
            },
            BumpType::Minor => Version {
                major: self.major,
                minor: self.minor + 1,
                patch: 0,
            },
            BumpType::Patch => Version {
                major: self.major,
                minor: self.minor,
                patch: self.patch + 1,
            },
            BumpType::None => self.clone(),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_version_parse() {
        let version = Version::parse("1.2.3").unwrap();
        assert_eq!(version.major, 1);
        assert_eq!(version.minor, 2);
        assert_eq!(version.patch, 3);
    }

    #[test]
    fn test_version_bump_major() {
        let version = Version::parse("1.2.3").unwrap();
        let bumped = version.bump(BumpType::Major);
        assert_eq!(bumped.to_string(), "2.0.0");
    }

    #[test]
    fn test_version_bump_minor() {
        let version = Version::parse("1.2.3").unwrap();
        let bumped = version.bump(BumpType::Minor);
        assert_eq!(bumped.to_string(), "1.3.0");
    }

    #[test]
    fn test_version_bump_patch() {
        let version = Version::parse("1.2.3").unwrap();
        let bumped = version.bump(BumpType::Patch);
        assert_eq!(bumped.to_string(), "1.2.4");
    }
}
