use knope_versioning::{
    GoVersioning, VersionedFile,
    package::BumpError,
    semver::{PreReleaseNotFound, Rule},
};
use miette::Diagnostic;

use crate::{
    RunType, fs, integrations::git, state::State, step::releases::package::execute_prepare_actions,
};

/// The implementation of [`crate::step::Step::BumpVersion`].
///
/// Bumps the version of every configured package using `rule`.
pub(crate) fn bump_version_and_update_state(
    state: RunType<State>,
    rule: &Rule,
) -> Result<RunType<State>, Error> {
    let (run_type, mut state) = state.take();

    for package in &mut state.packages {
        let (version, go_versioning) = if let Some(version) = package.override_version.clone() {
            (version, GoVersioning::BumpMajor)
        } else {
            (
                package.versioning.calculate_new_version(rule.clone())?,
                package.go_versioning,
            )
        };
        state.all_versioned_files =
            package
                .versioning
                .set_version(version, go_versioning, state.all_versioned_files)?;
    }
    let write_files = state
        .all_versioned_files
        .drain(..)
        .filter_map(VersionedFile::write)
        .flatten();
    execute_prepare_actions(run_type.of(write_files), false)?;
    Ok(run_type.of(state))
}
#[derive(Debug, Diagnostic, thiserror::Error)]
pub(crate) enum Error {
    #[error(transparent)]
    InvalidPreReleaseVersion(#[from] PreReleaseNotFound),
    #[error(transparent)]
    #[diagnostic(transparent)]
    Git(#[from] git::Error),
    #[error(transparent)]
    #[diagnostic(transparent)]
    UpdatePackageVersion(#[from] BumpError),
    #[error(transparent)]
    #[diagnostic(transparent)]
    Fs(#[from] fs::Error),
}
