//! Hook configuration for mi6.
//!
//! This module defines which hook events are enabled for capture.

use serde::{Deserialize, Serialize};

use crate::model::EventType;

/// Macro to define HooksConfig with automatic snake_case to PascalCase mapping.
///
/// This macro generates the struct, Default impl, and enabled_hooks() method
/// from a single definition, ensuring the field names and EventType variants
/// are always in sync.
macro_rules! define_hooks_config {
    ($($field:ident => $variant:ident),* $(,)?) => {
        #[derive(Debug, Clone, Serialize, Deserialize)]
        #[serde(rename_all = "PascalCase")]
        pub struct HooksConfig {
            $(
                #[serde(default = "default_true")]
                pub $field: bool,
            )*
        }

        impl Default for HooksConfig {
            fn default() -> Self {
                Self {
                    $($field: true,)*
                }
            }
        }

        impl HooksConfig {
            /// Returns enabled hooks as EventType values for type-safe handling.
            pub fn enabled_hooks(&self) -> Vec<EventType> {
                let mut hooks = Vec::new();
                $(
                    if self.$field {
                        hooks.push(EventType::$variant);
                    }
                )*
                hooks
            }
        }
    };
}

define_hooks_config! {
    session_start => SessionStart,
    session_end => SessionEnd,
    user_prompt_submit => UserPromptSubmit,
    stop => Stop,
    subagent_start => SubagentStart,
    subagent_stop => SubagentStop,
    notification => Notification,
    permission_request => PermissionRequest,
    pre_compact => PreCompact,
    pre_tool_use => PreToolUse,
    post_tool_use => PostToolUse,
}

fn default_true() -> bool {
    true
}

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

    #[test]
    fn test_enabled_hooks_returns_all_event_types() {
        let config = HooksConfig::default();
        let hooks = config.enabled_hooks();

        // Verify all expected hooks are present as EventType variants
        assert!(hooks.contains(&EventType::SessionStart));
        assert!(hooks.contains(&EventType::SessionEnd));
        assert!(hooks.contains(&EventType::UserPromptSubmit));
        assert!(hooks.contains(&EventType::Stop));
        assert!(hooks.contains(&EventType::SubagentStart));
        assert!(hooks.contains(&EventType::SubagentStop));
        assert!(hooks.contains(&EventType::Notification));
        assert!(hooks.contains(&EventType::PermissionRequest));
        assert!(hooks.contains(&EventType::PreCompact));
        assert!(hooks.contains(&EventType::PreToolUse));
        assert!(hooks.contains(&EventType::PostToolUse));

        // Verify we have exactly 11 hooks
        assert_eq!(hooks.len(), 11);
    }

    #[test]
    fn test_enabled_hooks_respects_disabled_hooks() {
        let config = HooksConfig {
            session_start: false,
            pre_tool_use: false,
            ..Default::default()
        };

        let hooks = config.enabled_hooks();
        // 11 total hooks - 2 disabled = 9
        assert_eq!(hooks.len(), 9);
        assert!(!hooks.contains(&EventType::SessionStart));
        assert!(!hooks.contains(&EventType::PreToolUse));
        assert!(hooks.contains(&EventType::SessionEnd));
    }
}
