pub(crate) struct AnonymousDefinition;

use crate::{
    audit::AuditError,
    finding::{Confidence, Persona, Severity, location::Locatable as _},
    state::AuditState,
};

use super::{Audit, AuditLoadError, Job, audit_meta};

// Workflows without a name can be hard to find in the GitHub UI, so
// severity is set higher than for Job.
const ANONYMOUS_DEFINITION_WORKFLOW_SEVERITY: Severity = Severity::Low;
const ANONYMOUS_DEFINITION_JOB_SEVERITY: Severity = Severity::Informational;

audit_meta!(
    AnonymousDefinition,
    "anonymous-definition",
    "workflow or action definition without a name"
);

#[async_trait::async_trait]
impl Audit for AnonymousDefinition {
    fn new(_state: &AuditState) -> Result<Self, AuditLoadError> {
        Ok(Self)
    }

    async fn audit_workflow<'doc>(
        &self,
        workflow: &'doc crate::models::workflow::Workflow,
        _config: &crate::config::Config,
    ) -> Result<Vec<crate::finding::Finding<'doc>>, AuditError> {
        let mut findings = vec![];

        if workflow.name.is_none() {
            findings.push(
                Self::finding()
                    .severity(ANONYMOUS_DEFINITION_WORKFLOW_SEVERITY)
                    .confidence(Confidence::High)
                    .persona(Persona::Pedantic)
                    .add_location(workflow.location().primary())
                    .tip("use 'name: ...' to give this workflow a name")
                    .build(workflow)?,
            );
        }

        for job in workflow.jobs() {
            match job {
                Job::NormalJob(normal) => {
                    if normal.name.is_none() {
                        findings.push(
                            Self::finding()
                                .severity(ANONYMOUS_DEFINITION_JOB_SEVERITY)
                                .confidence(Confidence::High)
                                .persona(Persona::Pedantic)
                                .add_location(normal.location_with_grip().primary())
                                .tip("use 'name: ...' to give this job a name")
                                .build(workflow)?,
                        );
                    }
                }
                _ => continue,
            }
        }

        Ok(findings)
    }
}
