"""
Hooks installation and settings.json wiring for CARL.
Handles copying hooks to ~/.claude/hooks/ and generating settings.json config.
Also handles hook version tracking and updates.
"""
import json
import re
import shutil
import subprocess
import sys
from pathlib import Path


def get_python_command() -> str:
    """Detect the correct Python command for this system.

    Checks python3 first (preferred on Unix), then python.
    Returns the command that works.
    """
    # Check what works on this system
    for cmd in ['python3', 'python']:
        try:
            result = subprocess.run(
                [cmd, '--version'],
                capture_output=True,
                timeout=5
            )
            if result.returncode == 0:
                return cmd
        except (subprocess.SubprocessError, FileNotFoundError):
            continue

    # Fallback based on platform
    if sys.platform == 'win32':
        return 'python'
    return 'python3'


# Cache the detected command
_PYTHON_CMD = None


def python_cmd() -> str:
    """Get cached Python command."""
    global _PYTHON_CMD
    if _PYTHON_CMD is None:
        _PYTHON_CMD = get_python_command()
    return _PYTHON_CMD

# Hooks bundled with this app
BUNDLED_HOOKS_DIR = Path(__file__).parent.parent / 'hooks'

# Hook files to install (CARL core + optional)
HOOK_FILES = [
    'carl-injector.v2.py',
]

# Optional hooks (user can choose to install)
OPTIONAL_HOOK_FILES = [
    'claudemd-reinject.py',
]

# Metadata for optional hooks
OPTIONAL_HOOKS_METADATA = {
    'claudemd-reinject.py': {
        'id': 'claudemd_reinject',
        'name': 'CLAUDE.md Reinject',
        'description': 'Re-inject CLAUDE.md when context drops below 60%',
        'hook_type': 'UserPromptSubmit',
        'manifest_key': 'ADDON_CLAUDEMD_REINJECT_STATE',
        'toggle_key': 'CLAUDEMD_REINJECT',  # Legacy, keep for compatibility
        'default_enabled': True,
        'position': 'after:carl-injector.v2.py'
    }
}

# Bundled hook versions - UPDATE THESE when modifying hooks
# Format: filename -> version string
BUNDLED_HOOK_VERSIONS = {
    'carl-injector.v2.py': '1.0.1',
    'claudemd-reinject.py': '1.0.0',
}

# Version header pattern in hook files
VERSION_PATTERN = re.compile(r'^#\s*CARL_HOOK_VERSION\s*=\s*([0-9]+\.[0-9]+\.[0-9]+)', re.MULTILINE)


def parse_hook_version(file_path: Path) -> str | None:
    """Extract version from a hook file's CARL_HOOK_VERSION header.

    Returns version string or None if not found.
    """
    try:
        # Read first 500 bytes (version should be near top)
        with open(file_path, 'r', encoding='utf-8') as f:
            header = f.read(500)

        match = VERSION_PATTERN.search(header)
        if match:
            return match.group(1)
        return None
    except Exception:
        return None


def compare_versions(v1: str, v2: str) -> int:
    """Compare two version strings.

    Returns:
        -1 if v1 < v2
         0 if v1 == v2
         1 if v1 > v2
    """
    def normalize(v):
        return [int(x) for x in v.split('.')]

    try:
        n1, n2 = normalize(v1), normalize(v2)
        # Pad to same length
        while len(n1) < len(n2):
            n1.append(0)
        while len(n2) < len(n1):
            n2.append(0)

        for a, b in zip(n1, n2):
            if a < b:
                return -1
            if a > b:
                return 1
        return 0
    except (ValueError, AttributeError):
        return 0


def check_hook_versions(workspace_path: Path = None) -> dict:
    """Check installed hooks against bundled versions.

    Checks both global (~/.claude/hooks) and workspace hooks.

    Args:
        workspace_path: Workspace to check for hooks.

    Returns:
        Dict with hooks needing updates and their version info.
    """
    global_hooks_dir = get_claude_hooks_dir()
    workspace_hooks_dir = workspace_path / '.claude' / 'hooks' if workspace_path else None

    updates_available = []
    hooks_status = []

    # Check all known hooks (core + optional)
    all_hooks = HOOK_FILES + OPTIONAL_HOOK_FILES

    for hook_file in all_hooks:
        bundled_version = BUNDLED_HOOK_VERSIONS.get(hook_file)
        if not bundled_version:
            continue

        # Check both locations - workspace takes priority
        installed_path = None
        installed_version = None
        location = None

        if workspace_hooks_dir and (workspace_hooks_dir / hook_file).exists():
            installed_path = workspace_hooks_dir / hook_file
            location = 'workspace'
        elif (global_hooks_dir / hook_file).exists():
            installed_path = global_hooks_dir / hook_file
            location = 'global'

        if installed_path:
            installed_version = parse_hook_version(installed_path)

        # Determine status
        needs_update = False
        if installed_version and bundled_version:
            needs_update = compare_versions(installed_version, bundled_version) < 0
        elif installed_path and not installed_version:
            # Installed but no version header = assume needs update
            needs_update = True

        hook_info = {
            'filename': hook_file,
            'bundled_version': bundled_version,
            'installed_version': installed_version,
            'installed_path': str(installed_path) if installed_path else None,
            'location': location,
            'installed': installed_path is not None,
            'needs_update': needs_update,
            'is_core': hook_file in HOOK_FILES
        }

        hooks_status.append(hook_info)

        if needs_update:
            updates_available.append(hook_info)

    return {
        'success': True,
        'updates_available': len(updates_available) > 0,
        'update_count': len(updates_available),
        'hooks': hooks_status,
        'hooks_needing_update': updates_available
    }


def update_hook(hook_file: str, workspace_path: Path = None, location: str = 'workspace') -> dict:
    """Update a single hook file to the bundled version.

    Args:
        hook_file: Name of the hook file to update
        workspace_path: Workspace path (required if location='workspace')
        location: 'global' or 'workspace' - where to update the hook

    Returns:
        Dict with success status and update details.
    """
    if hook_file not in BUNDLED_HOOK_VERSIONS:
        return {'success': False, 'error': f'Unknown hook file: {hook_file}'}

    src = BUNDLED_HOOKS_DIR / hook_file
    if not src.exists():
        return {'success': False, 'error': f'Bundled hook not found: {hook_file}'}

    # Determine destination
    if location == 'workspace':
        if not workspace_path:
            return {'success': False, 'error': 'workspace_path required for workspace location'}
        dst_dir = workspace_path / '.claude' / 'hooks'
    else:
        dst_dir = get_claude_hooks_dir()

    dst = dst_dir / hook_file

    # Check if hook exists at this location
    if not dst.exists():
        return {'success': False, 'error': f'Hook not installed at {location} location'}

    try:
        # Get versions for logging
        old_version = parse_hook_version(dst) or 'unknown'
        new_version = BUNDLED_HOOK_VERSIONS.get(hook_file)

        # Copy the new version
        shutil.copy2(src, dst)

        return {
            'success': True,
            'hook': hook_file,
            'location': location,
            'path': str(dst),
            'old_version': old_version,
            'new_version': new_version
        }
    except Exception as e:
        return {'success': False, 'error': str(e)}


def update_all_hooks(workspace_path: Path = None) -> dict:
    """Update all outdated hooks.

    Args:
        workspace_path: Workspace to update hooks for.

    Returns:
        Dict with results for each hook updated.
    """
    status = check_hook_versions(workspace_path)

    if not status.get('updates_available'):
        return {
            'success': True,
            'updated': [],
            'message': 'All hooks are up to date'
        }

    updated = []
    errors = []

    for hook_info in status.get('hooks_needing_update', []):
        result = update_hook(
            hook_info['filename'],
            workspace_path,
            hook_info.get('location', 'workspace')
        )

        if result.get('success'):
            updated.append(result)
        else:
            errors.append({
                'hook': hook_info['filename'],
                'error': result.get('error')
            })

    return {
        'success': len(errors) == 0,
        'updated': updated,
        'errors': errors
    }


def get_claude_hooks_dir() -> Path:
    """Get the ~/.claude/hooks directory path."""
    return Path.home() / '.claude' / 'hooks'


def get_claude_settings_path() -> Path:
    """Get the ~/.claude/settings.json path."""
    return Path.home() / '.claude' / 'settings.json'


def check_hooks_wired(workspace_path: Path = None) -> bool:
    """Check if CARL hooks are wired in settings.json.

    Args:
        workspace_path: Optional workspace path to also check project-level settings.
    """
    # Paths to check
    settings_paths = [get_claude_settings_path()]  # Global settings

    # Also check project-level settings if workspace provided
    if workspace_path:
        project_settings = workspace_path / '.claude' / 'settings.json'
        if project_settings.exists():
            settings_paths.append(project_settings)

    for settings_path in settings_paths:
        if not settings_path.exists():
            continue

        try:
            with open(settings_path, 'r') as f:
                settings = json.load(f)

            hooks = settings.get('hooks', {})
            user_prompt_hooks = hooks.get('UserPromptSubmit', [])

            # Check if carl-injector.v2.py is in any hook command
            for item in user_prompt_hooks:
                # Handle complex format: {"hooks": [...], "matcher": "..."}
                if isinstance(item, dict) and 'hooks' in item:
                    for hook in item.get('hooks', []):
                        if isinstance(hook, dict) and 'carl-injector' in hook.get('command', ''):
                            return True
                # Handle simple format: {"type": "command", "command": "..."}
                elif isinstance(item, dict) and 'command' in item:
                    if 'carl-injector' in item.get('command', ''):
                        return True
        except Exception:
            continue

    return False


def check_hooks_status(workspace_path: Path = None) -> dict:
    """Check which hooks are installed, their paths, and wiring status.

    Args:
        workspace_path: Optional workspace path to also check for hooks.
                       Will check both workspace/.claude/hooks/ and ~/.claude/hooks/
    """
    global_hooks_dir = get_claude_hooks_dir()

    # Also check workspace hooks directory if provided
    workspace_hooks_dir = None
    if workspace_path:
        workspace_hooks_dir = workspace_path / '.claude' / 'hooks'

    # Check if hooks are wired in settings.json (global or project-level)
    wired = check_hooks_wired(workspace_path)

    status = {
        'hooks_dir': str(global_hooks_dir),
        'hooks_dir_exists': global_hooks_dir.exists(),
        'workspace_hooks_dir': str(workspace_hooks_dir) if workspace_hooks_dir else None,
        'workspace_hooks_dir_exists': workspace_hooks_dir.exists() if workspace_hooks_dir else False,
        'wired': wired,
        'hooks': {}
    }

    for hook_file in HOOK_FILES:
        # Check both global and workspace locations
        global_path = global_hooks_dir / hook_file
        workspace_path_hook = workspace_hooks_dir / hook_file if workspace_hooks_dir else None

        installed_globally = global_path.exists()
        installed_in_workspace = workspace_path_hook.exists() if workspace_path_hook else False
        installed = installed_globally or installed_in_workspace

        # Report the path where it was found
        if installed_in_workspace:
            found_path = str(workspace_path_hook)
        elif installed_globally:
            found_path = str(global_path)
        else:
            found_path = str(global_path)  # Default to global for "not found"

        status['hooks'][hook_file] = {
            'installed': installed,
            'installed_globally': installed_globally,
            'installed_in_workspace': installed_in_workspace,
            'path': found_path
        }

    # Convenience flags
    all_installed = all(h['installed'] for h in status['hooks'].values())
    status['all_installed'] = all_installed
    status['fully_configured'] = all_installed and wired

    return status


def install_hooks(location: str = 'global', workspace_path: Path = None) -> dict:
    """Copy bundled hooks to specified location.

    Args:
        location: 'global' (~/.claude/hooks/) or 'project' (<workspace>/.claude/hooks/)
        workspace_path: Required if location is 'project'

    Returns:
        Dict with success status and installation details.
    """
    # Determine target directory
    if location == 'project':
        if not workspace_path:
            return {'success': False, 'error': 'workspace_path required for project location'}
        hooks_dir = workspace_path / '.claude' / 'hooks'
    else:
        hooks_dir = get_claude_hooks_dir()

    try:
        # Create hooks directory if needed
        hooks_dir.mkdir(parents=True, exist_ok=True)

        installed = []
        errors = []

        for hook_file in HOOK_FILES:
            src = BUNDLED_HOOKS_DIR / hook_file
            dst = hooks_dir / hook_file

            if not src.exists():
                errors.append(f"Source not found: {hook_file}")
                continue

            try:
                shutil.copy2(src, dst)
                installed.append(hook_file)
            except Exception as e:
                errors.append(f"{hook_file}: {str(e)}")

        return {
            'success': len(errors) == 0,
            'installed': installed,
            'errors': errors,
            'hooks_dir': str(hooks_dir),
            'location': location
        }

    except Exception as e:
        return {
            'success': False,
            'error': str(e)
        }


def get_settings_json_snippet() -> str:
    """Generate the settings.json hooks configuration snippet."""
    hooks_dir = get_claude_hooks_dir()

    # Helper to format path with forward slashes
    def hook_path(filename):
        return str(hooks_dir / filename).replace('\\', '/')

    py = python_cmd()

    # Build the hooks configuration (CARL injector only)
    hooks_config = {
        "hooks": {
            "UserPromptSubmit": [
                {
                    "type": "command",
                    "command": f"{py} {hook_path('carl-injector.v2.py')}"
                }
            ]
        }
    }

    return json.dumps(hooks_config, indent=2)


def get_claude_prompt() -> str:
    """Generate a prompt for Claude Code to wire up the CARL hook."""
    hooks_dir = get_claude_hooks_dir()
    settings_path = get_claude_settings_path()

    # Helper to format path with forward slashes
    def hook_path(filename):
        return str(hooks_dir / filename).replace('\\', '/')

    py = python_cmd()

    return f"""Please add the CARL hook to my Claude Code settings.

The hook is installed at: {hooks_dir}

Add this to my settings.json at {settings_path}:

In the "hooks" section, add this hook (merge with existing, don't overwrite):

"UserPromptSubmit": [
  {{
    "type": "command",
    "command": "{py} {hook_path('carl-injector.v2.py')}"
  }}
]

If the hooks section doesn't exist, create it. IMPORTANT: Merge with any existing hooks - do not overwrite."""


def auto_update_settings() -> dict:
    """Automatically update settings.json with hooks configuration.

    Properly merges with existing hooks instead of overwriting.
    Handles both simple format and complex format with matchers.
    """
    settings_path = get_claude_settings_path()
    hooks_dir = get_claude_hooks_dir()

    try:
        # Load existing settings or create new
        if settings_path.exists():
            with open(settings_path, 'r') as f:
                settings = json.load(f)
        else:
            settings_path.parent.mkdir(parents=True, exist_ok=True)
            settings = {}

        # Ensure hooks section exists
        if 'hooks' not in settings:
            settings['hooks'] = {}

        # Build hook command - detect python/python3 and use forward slashes
        py = python_cmd()

        def make_hook(filename):
            # Convert path to forward slashes for cross-platform compatibility
            hook_path = str(hooks_dir / filename).replace('\\', '/')
            return {
                "type": "command",
                "command": f"{py} {hook_path}"
            }

        # Check if a hook command already exists (by checking command substring)
        def hook_exists(hooks_list, filename):
            """Check if a hook with this filename already exists in the hooks list."""
            for item in hooks_list:
                # Handle complex format: {"hooks": [...], "matcher": "..."}
                if isinstance(item, dict) and 'hooks' in item:
                    for hook in item.get('hooks', []):
                        if isinstance(hook, dict) and filename in hook.get('command', ''):
                            return True
                # Handle simple format: {"type": "command", "command": "..."}
                elif isinstance(item, dict) and 'command' in item:
                    if filename in item.get('command', ''):
                        return True
            return False

        def append_hooks_to_event(event_name, new_hooks):
            """Append hooks to an event type, handling both formats."""
            existing = settings['hooks'].get(event_name, [])

            if not existing:
                # No existing hooks - create new with complex format for consistency
                settings['hooks'][event_name] = [{"hooks": new_hooks}]
                return

            # Check format of existing hooks
            first_item = existing[0] if existing else None

            if first_item and isinstance(first_item, dict) and 'hooks' in first_item:
                # Complex format - find the default (no matcher) entry and append
                default_entry = None
                for entry in existing:
                    if 'matcher' not in entry:
                        default_entry = entry
                        break

                if default_entry:
                    # Append to existing default entry
                    for hook in new_hooks:
                        # Extract filename from command for duplicate check
                        cmd = hook.get('command', '')
                        filename = cmd.split('/')[-1].split('\\')[-1].replace('"', '')
                        if not hook_exists(existing, filename):
                            default_entry['hooks'].append(hook)
                else:
                    # No default entry - create one
                    existing.insert(0, {"hooks": new_hooks})
            else:
                # Simple format - append directly
                for hook in new_hooks:
                    cmd = hook.get('command', '')
                    filename = cmd.split('/')[-1].split('\\')[-1].replace('"', '')
                    if not hook_exists(existing, filename):
                        existing.append(hook)
                settings['hooks'][event_name] = existing

        # Define which hooks go where (CARL injector only)
        hooks_to_add = {
            'UserPromptSubmit': [
                make_hook('carl-injector.v2.py')
            ]
        }

        # Append each hook type
        for event_name, hooks in hooks_to_add.items():
            append_hooks_to_event(event_name, hooks)

        # Write back
        with open(settings_path, 'w') as f:
            json.dump(settings, f, indent=2)

        return {
            'success': True,
            'settings_path': str(settings_path)
        }

    except Exception as e:
        return {
            'success': False,
            'error': str(e)
        }


def check_optional_hooks_status(workspace_path: Path = None, manifest_manager=None) -> dict:
    """Check which optional hooks are installed and wired.

    Args:
        workspace_path: Workspace path to check for hooks installation.
        manifest_manager: Optional ManifestManager to read global enabled state.

    Returns:
        Dict with hooks list containing status, metadata, and global_enabled.
    """
    if workspace_path is None:
        return {'error': 'workspace_path is required', 'hooks': []}

    workspace_hooks_dir = workspace_path / '.claude' / 'hooks'
    settings_path = workspace_path / '.claude' / 'settings.json'

    # Load settings to check wiring
    settings = {}
    if settings_path.exists():
        try:
            with open(settings_path, 'r') as f:
                settings = json.load(f)
        except Exception:
            pass

    # Read manifest toggles for global_enabled state
    manifest_toggles = {}
    if manifest_manager:
        manifest_toggles = manifest_manager.read_toggles()

    hooks_list = []

    for hook_file in OPTIONAL_HOOK_FILES:
        metadata = OPTIONAL_HOOKS_METADATA.get(hook_file, {})
        hook_path = workspace_hooks_dir / hook_file
        manifest_key = metadata.get('manifest_key', '')

        # Check if installed (file exists)
        installed = hook_path.exists()

        # Check if wired in settings.json
        wired = False
        hooks_config = settings.get('hooks', {})
        user_prompt_hooks = hooks_config.get('UserPromptSubmit', [])

        for item in user_prompt_hooks:
            # Handle complex format: {"hooks": [...]}
            if isinstance(item, dict) and 'hooks' in item:
                for hook in item.get('hooks', []):
                    if isinstance(hook, dict) and hook_file in hook.get('command', ''):
                        wired = True
                        break
            # Handle simple format: {"type": "command", "command": "..."}
            elif isinstance(item, dict) and hook_file in item.get('command', ''):
                wired = True
                break
            if wired:
                break

        # Determine three-state status
        if wired:
            status = 'wired'
        elif installed:
            status = 'installed'
        else:
            status = 'not_installed'

        # Get global_enabled from manifest (default to True if not set)
        global_enabled = manifest_toggles.get(manifest_key, metadata.get('default_enabled', True))

        hooks_list.append({
            'id': metadata.get('id', hook_file.replace('.py', '').replace('-', '_')),
            'filename': hook_file,
            'name': metadata.get('name', hook_file),
            'description': metadata.get('description', ''),
            'hook_type': metadata.get('hook_type', 'UserPromptSubmit'),
            'status': status,
            'installed': installed,
            'wired': wired,
            'global_enabled': global_enabled,
            'manifest_key': manifest_key,
            'path': str(hook_path),
            'default_enabled': metadata.get('default_enabled', True)
        })

    return {'success': True, 'hooks': hooks_list}


def install_optional_hook(hook_name: str, workspace_path: Path = None) -> dict:
    """Install an optional hook file to workspace (does NOT wire to settings.json).

    Args:
        hook_name: Name of the hook file (e.g., 'claudemd-reinject.py')
        workspace_path: Workspace path to install hook to.

    Returns:
        Dict with success status. Status will be 'installed' (not 'wired').
    """
    if workspace_path is None:
        return {'success': False, 'error': 'workspace_path is required'}

    if hook_name not in OPTIONAL_HOOK_FILES:
        return {'success': False, 'error': f'Unknown optional hook: {hook_name}'}

    workspace_hooks_dir = workspace_path / '.claude' / 'hooks'

    try:
        # Create hooks directory if needed
        workspace_hooks_dir.mkdir(parents=True, exist_ok=True)

        # Copy hook from bundled directory
        src = BUNDLED_HOOKS_DIR / hook_name
        dst = workspace_hooks_dir / hook_name

        if not src.exists():
            return {'success': False, 'error': f'Bundled hook not found: {hook_name}'}

        shutil.copy2(src, dst)

        return {
            'success': True,
            'status': 'installed',
            'installed_path': str(dst)
        }

    except Exception as e:
        return {'success': False, 'error': str(e)}


def wire_optional_hook(hook_name: str, workspace_path: Path = None) -> dict:
    """Wire an installed optional hook to settings.json.

    Args:
        hook_name: Name of the hook file (e.g., 'claudemd-reinject.py')
        workspace_path: Workspace path where hook is installed.

    Returns:
        Dict with success status. Status will be 'wired' on success.
    """
    if workspace_path is None:
        return {'success': False, 'error': 'workspace_path is required'}

    if hook_name not in OPTIONAL_HOOK_FILES:
        return {'success': False, 'error': f'Unknown optional hook: {hook_name}'}

    metadata = OPTIONAL_HOOKS_METADATA.get(hook_name, {})
    workspace_hooks_dir = workspace_path / '.claude' / 'hooks'
    settings_path = workspace_path / '.claude' / 'settings.json'
    hook_file_path = workspace_hooks_dir / hook_name

    # Check if hook file is installed
    if not hook_file_path.exists():
        return {'success': False, 'error': 'Hook file not installed. Install first.'}

    try:
        # Load or create settings
        if settings_path.exists():
            with open(settings_path, 'r') as f:
                settings = json.load(f)
        else:
            settings_path.parent.mkdir(parents=True, exist_ok=True)
            settings = {}

        # Ensure hooks section exists
        if 'hooks' not in settings:
            settings['hooks'] = {}
        if 'UserPromptSubmit' not in settings['hooks']:
            settings['hooks']['UserPromptSubmit'] = [{'hooks': []}]

        # Build hook command
        py = python_cmd()
        hook_path_str = str(hook_file_path).replace('\\', '/')
        new_hook = {
            'type': 'command',
            'command': f'{py} {hook_path_str}'
        }

        # Get UserPromptSubmit hooks list
        user_prompt = settings['hooks']['UserPromptSubmit']

        # Find the hooks array (complex format)
        hooks_array = None
        for item in user_prompt:
            if isinstance(item, dict) and 'hooks' in item and 'matcher' not in item:
                hooks_array = item['hooks']
                break

        if hooks_array is None:
            # Create default entry
            user_prompt.insert(0, {'hooks': []})
            hooks_array = user_prompt[0]['hooks']

        # Check if already wired
        already_wired = any(hook_name in h.get('command', '') for h in hooks_array if isinstance(h, dict))
        if already_wired:
            return {'success': True, 'status': 'wired', 'message': 'Hook already wired'}

        # Find insertion position based on metadata
        position = metadata.get('position', '')
        insert_idx = len(hooks_array)  # Default: append at end

        if position.startswith('after:'):
            after_hook = position[6:]
            for i, hook in enumerate(hooks_array):
                if isinstance(hook, dict) and after_hook in hook.get('command', ''):
                    insert_idx = i + 1
                    break

        # Insert at position
        hooks_array.insert(insert_idx, new_hook)

        # Write settings back
        with open(settings_path, 'w') as f:
            json.dump(settings, f, indent=2)

        return {
            'success': True,
            'status': 'wired'
        }

    except Exception as e:
        return {'success': False, 'error': str(e)}


def get_optional_hook_snippet(hook_name: str, workspace_path: Path = None) -> dict:
    """Get the settings.json snippet for manually wiring an optional hook.

    Args:
        hook_name: Name of the hook file
        workspace_path: Workspace path where hook is installed

    Returns:
        Dict with snippet string for settings.json
    """
    if hook_name not in OPTIONAL_HOOK_FILES:
        return {'success': False, 'error': f'Unknown optional hook: {hook_name}'}

    metadata = OPTIONAL_HOOKS_METADATA.get(hook_name, {})
    workspace_hooks_dir = workspace_path / '.claude' / 'hooks' if workspace_path else get_claude_hooks_dir()
    hook_path = str(workspace_hooks_dir / hook_name).replace('\\', '/')

    py = python_cmd()

    snippet = {
        "type": "command",
        "command": f"{py} {hook_path}"
    }

    return {
        'success': True,
        'snippet': json.dumps(snippet, indent=2),
        'hook_name': metadata.get('name', hook_name),
        'description': metadata.get('description', ''),
        'instruction': f'Add this to the "hooks" array in UserPromptSubmit section of settings.json'
    }


def toggle_optional_hook(hook_name: str, enabled: bool, manifest_manager) -> dict:
    """Toggle the global enabled state of an optional hook in manifest.

    Args:
        hook_name: Name of the hook file
        enabled: New enabled state
        manifest_manager: ManifestManager instance to update

    Returns:
        Dict with success status and new enabled state
    """
    if hook_name not in OPTIONAL_HOOK_FILES:
        return {'success': False, 'error': f'Unknown optional hook: {hook_name}'}

    if not manifest_manager:
        return {'success': False, 'error': 'No manifest manager available'}

    metadata = OPTIONAL_HOOKS_METADATA.get(hook_name, {})
    manifest_key = metadata.get('manifest_key')

    if not manifest_key:
        return {'success': False, 'error': 'Hook has no manifest_key defined'}

    try:
        success = manifest_manager.write_toggle(manifest_key, enabled)
        return {
            'success': success,
            'enabled': enabled,
            'manifest_key': manifest_key
        }
    except Exception as e:
        return {'success': False, 'error': str(e)}


def uninstall_optional_hook(hook_name: str, workspace_path: Path = None) -> dict:
    """Uninstall an optional hook by removing it from settings.json.

    Note: Keeps the file for easy reinstallation, only unwires from settings.

    Args:
        hook_name: Name of the hook file (e.g., 'claudemd-reinject.py')
        workspace_path: Workspace path where hook is installed.

    Returns:
        Dict with success status.
    """
    if workspace_path is None:
        return {'success': False, 'error': 'workspace_path is required'}

    if hook_name not in OPTIONAL_HOOK_FILES:
        return {'success': False, 'error': f'Unknown optional hook: {hook_name}'}

    settings_path = workspace_path / '.claude' / 'settings.json'

    if not settings_path.exists():
        return {'success': True, 'message': 'No settings.json found, nothing to unwire'}

    try:
        with open(settings_path, 'r') as f:
            settings = json.load(f)

        # Find and remove the hook from UserPromptSubmit
        hooks_config = settings.get('hooks', {})
        user_prompt = hooks_config.get('UserPromptSubmit', [])

        modified = False
        for item in user_prompt:
            if isinstance(item, dict) and 'hooks' in item:
                hooks_array = item['hooks']
                # Filter out the hook
                new_hooks = [h for h in hooks_array if not (isinstance(h, dict) and hook_name in h.get('command', ''))]
                if len(new_hooks) != len(hooks_array):
                    item['hooks'] = new_hooks
                    modified = True
            elif isinstance(item, dict) and hook_name in item.get('command', ''):
                user_prompt.remove(item)
                modified = True

        if modified:
            with open(settings_path, 'w') as f:
                json.dump(settings, f, indent=2)

        return {
            'success': True,
            'unwired': modified,
            'file_kept': True  # We don't delete the file
        }

    except Exception as e:
        return {'success': False, 'error': str(e)}
