use model::repos::RepoProtectModel;

use crate::ssh::ref_update::RefUpdate;

fn ref_matches_protection(ref_name: &str, protection_pattern: &str) -> bool {
    ref_name == protection_pattern
        || ref_name.starts_with(&format!("{}/", protection_pattern))
}

pub fn check_branch_protection(
    branch_protects: &[RepoProtectModel],
    r#ref: &RefUpdate,
) -> Option<String> {
    for protection in branch_protects {
        if !ref_matches_protection(&r#ref.name, &protection.pattern) {
            continue;
        }

        if r#ref.new_oid == "0000000000000000000000000000000000000000" {
            if !protection.allow_deletions {
                return Some(format!(
                    "protected branch rejected. Deletion of '{}' is forbidden. Create a PR or ask a maintainer to update branch protection.",
                    r#ref.name
                ));
            }
            continue;
        }

        if r#ref.name.starts_with("refs/tags/") {
            continue;
        }

        let is_new_branch =
            r#ref.old_oid == "0000000000000000000000000000000000000000";
        if !is_new_branch
            && r#ref.old_oid != r#ref.new_oid
            && r#ref.name.starts_with("refs/heads/")
            && !protection.allow_force_pushes
        {
            return Some(format!(
                "protected branch rejected. Force push to '{}' is forbidden. Create a PR instead of rewriting protected history.",
                r#ref.name
            ));
        }

        if protection.require_pull_request {
            return Some(format!(
                "protected branch rejected. Direct push to '{}' is forbidden. Please push to a feature branch and create a PR.",
                r#ref.name
            ));
        }
    }
    None
}
