//! `Adapter` contract impl for Git hooks.

use std::path::Path;

use shackles_core::{
    Adapter, AdapterError, AdapterRequirement, EngineRequirementOutput, InitCommand,
    LinterCommand, Provenance, ValidationCommand, shell_quote_arg,
};

use crate::runtime::build::lower_git_hooks_requirement;
use crate::types::{ADAPTER_ID, GitHooksAdapter, GitHooksAdapterRequirement};

impl Adapter for GitHooksAdapter {
    fn id(&self) -> &'static str {
        ADAPTER_ID
    }

    fn lower(
        &self,
        provenance: Provenance,
        requirement: Box<dyn AdapterRequirement>,
    ) -> Result<EngineRequirementOutput, AdapterError> {
        let Some(req) = requirement
            .as_any()
            .downcast_ref::<GitHooksAdapterRequirement>()
        else {
            return Err(AdapterError::WrongRequirementType {
                adapter_id: ADAPTER_ID,
                expected: "GitHooksAdapterRequirement",
            });
        };
        Ok(lower_git_hooks_requirement(provenance, req.clone()))
    }

    fn linter_command(&self) -> Option<LinterCommand> {
        None
    }

    fn validation_commands(&self, target_root: &Path) -> Vec<ValidationCommand> {
        let repo = shell_quote_arg(&target_root.display().to_string());
        vec![ValidationCommand {
            adapter_id: ADAPTER_ID,
            command_id: "git-hooks-path",
            command: format!(
                "test \"$(git -C {repo} config --get core.hooksPath)\" = .githooks"
            ),
        }]
    }

    fn init_commands(&self, target_root: &Path) -> Vec<InitCommand> {
        let repo = shell_quote_arg(&target_root.display().to_string());
        vec![InitCommand {
            adapter_id: ADAPTER_ID,
            command_id: "git-hooks-path",
            command: format!("git -C {repo} config core.hooksPath .githooks"),
        }]
    }
}
