"""
Hook Manager

Provides a centralized system for managing and executing hooks.
"""

import logging
from typing import Optional

from groknroll.plugins.base import Hook, HookContext, HookResult, HookType

logger = logging.getLogger(__name__)


class HookManager:
    """
    Manager for hook registration and execution

    Example:
        manager = HookManager()

        # Register a hook
        def my_hook(ctx: HookContext) -> HookResult:
            print(f"Hook triggered: {ctx.hook_type}")
            return HookResult(success=True)

        manager.register(HookType.BEFORE_WRITE, my_hook)

        # Trigger hook
        ctx = HookContext(hook_type=HookType.BEFORE_WRITE, data={"path": "/file.txt"})
        results = manager.trigger(HookType.BEFORE_WRITE, ctx)
    """

    def __init__(self):
        self._hooks: dict[HookType, list[Hook]] = {ht: [] for ht in HookType}

    def register(self, hook: Hook) -> None:
        """
        Register a hook

        Args:
            hook: Hook to register
        """
        self._hooks[hook.hook_type].append(hook)
        self._hooks[hook.hook_type].sort(key=lambda h: -h.priority)
        logger.debug(f"Registered hook: {hook.hook_type.value} (priority: {hook.priority})")

    def unregister(self, hook_type: HookType, plugin_name: Optional[str] = None) -> int:
        """
        Unregister hooks

        Args:
            hook_type: Type of hook to unregister
            plugin_name: Only unregister hooks from this plugin

        Returns:
            Number of hooks unregistered
        """
        original_count = len(self._hooks[hook_type])
        if plugin_name:
            self._hooks[hook_type] = [
                h for h in self._hooks[hook_type] if h.plugin_name != plugin_name
            ]
        else:
            self._hooks[hook_type] = []
        return original_count - len(self._hooks[hook_type])

    def unregister_all(self, plugin_name: str) -> int:
        """
        Unregister all hooks from a plugin

        Args:
            plugin_name: Plugin name

        Returns:
            Total number of hooks unregistered
        """
        count = 0
        for hook_type in HookType:
            count += self.unregister(hook_type, plugin_name)
        return count

    def trigger(self, hook_type: HookType, context: HookContext) -> list[HookResult]:
        """
        Trigger all hooks of a type

        Args:
            hook_type: Type of hook to trigger
            context: Context to pass to hooks

        Returns:
            List of results from each hook
        """
        results = []
        current_data = context.data.copy()

        for hook in self._hooks[hook_type]:
            try:
                ctx = HookContext(
                    hook_type=hook_type,
                    data=current_data,
                    metadata=context.metadata,
                )
                result = hook.handler(ctx)
                results.append(result)

                # Update data if modified
                if result.modified_data:
                    current_data = result.modified_data

                # Stop chain if requested
                if not result.should_continue:
                    break

            except Exception as e:
                logger.error(f"Hook {hook.plugin_name}:{hook_type.value} failed: {e}")
                results.append(HookResult(success=False, error=str(e)))

        return results

    def trigger_single(self, hook_type: HookType, context: HookContext) -> HookResult:
        """
        Trigger hooks and return combined result

        Args:
            hook_type: Type of hook to trigger
            context: Context to pass to hooks

        Returns:
            Combined result (success if all succeeded)
        """
        results = self.trigger(hook_type, context)
        if not results:
            return HookResult(success=True)

        all_success = all(r.success for r in results)
        final_data = results[-1].modified_data if results else None
        errors = [r.error for r in results if r.error]

        return HookResult(
            success=all_success,
            modified_data=final_data,
            error="; ".join(errors) if errors else None,
        )

    def get_hooks(self, hook_type: HookType) -> list[Hook]:
        """Get all registered hooks for a type"""
        return self._hooks[hook_type].copy()

    def has_hooks(self, hook_type: HookType) -> bool:
        """Check if any hooks are registered for a type"""
        return len(self._hooks[hook_type]) > 0


# Global hook manager
_hook_manager: Optional[HookManager] = None


def get_hook_manager() -> HookManager:
    """Get the global hook manager"""
    global _hook_manager
    if _hook_manager is None:
        _hook_manager = HookManager()
    return _hook_manager


def reset_hook_manager() -> None:
    """Reset the global hook manager (for testing)"""
    global _hook_manager
    _hook_manager = None
