"""Hook configuration sync for CLI agent integrations.

Can be invoked automatically (opt-in via STASO_AUTO_SYNC=1) on SessionStart,
or manually via ``staso sync [--target <agent>]``.
"""
from __future__ import annotations

import json
import logging
import os
import re
import sys
from pathlib import Path

logger = logging.getLogger("staso")


def auto_sync_enabled() -> bool:
    """Check if auto-repair is enabled via environment variable."""
    return os.environ.get("STASO_AUTO_SYNC", "").lower() in ("1", "true")


def repair_hooks(agent_name: str, cwd: str = "") -> bool:
    """Ensure all hook events for an agent are registered in its settings file.

    Returns True if repairs were made, False if config was already correct
    or no settings file was found.
    """
    from staso.cli import (
        _build_hooks_config,
        _is_staso_hook,
        _merge_settings,
        get_agent,
    )

    agent = get_agent(agent_name)
    if agent is None:
        logger.warning("staso: unknown agent '%s' for repair", agent_name)
        return False

    candidates = _settings_candidates(agent, cwd)
    settings_path, existing = _find_settings_with_staso_hooks(candidates)

    if settings_path is None:
        return False

    existing_hooks = existing.get("hooks", {})
    all_present = all(
        any(_is_staso_hook(e) for e in existing_hooks.get(event, []))
        for event in agent.hook_events
    )
    if all_present:
        return False

    command = _extract_staso_command(existing_hooks, agent.module)
    if not command:
        return False

    merged = _merge_settings(existing, _build_hooks_config(command, agent), {})
    try:
        settings_path.write_text(json.dumps(merged, indent=2), encoding="utf-8")
        logger.debug("staso: repaired hooks config (%s)", settings_path)
        return True
    except OSError:
        return False


def _settings_candidates(agent: object, cwd: str) -> list[Path]:
    """Return candidate settings file paths for an agent."""
    candidates: list[Path] = []
    if cwd:
        candidates.append(Path(cwd) / agent.project_settings)  # type: ignore[attr-defined]
    candidates.append(Path.home() / agent.global_settings)  # type: ignore[attr-defined]
    return candidates


def _find_settings_with_staso_hooks(
    candidates: list[Path],
) -> tuple[Path | None, dict]:
    """Find the first settings file containing staso hooks."""
    from staso.cli import _is_staso_hook

    for path in candidates:
        if not path.exists():
            continue
        try:
            data = json.loads(path.read_text(encoding="utf-8"))
        except (json.JSONDecodeError, OSError):
            continue
        hooks = data.get("hooks", {})
        if any(_is_staso_hook(e) for entries in hooks.values() for e in entries):
            return path, data
    return None, {}


def _extract_staso_command(hooks: dict, module: str) -> str | None:
    """Extract the staso command string from existing hook entries."""
    from staso.cli import _is_staso_hook

    target = f"staso.{module}"
    for event_entries in hooks.values():
        for entry in event_entries:
            if not _is_staso_hook(entry):
                continue
            for h in entry.get("hooks", [entry]):
                cmd = h.get("command", "")
                if target in cmd:
                    return cmd
    return None


# ---------------------------------------------------------------------------
# Python path sync
# ---------------------------------------------------------------------------

# Matches an absolute path to a python executable before `-m staso.`
_PYTHON_PATH_RE = re.compile(r"(/\S+/python[0-9.]*)\s+-m\s+staso\.")



def sync_python_path(agent_name: str, cwd: str = "") -> bool:
    """Update the Python path in hook commands to match current sys.executable.

    Returns True if changes were made.
    """
    from staso.cli import _is_staso_hook, get_agent

    agent = get_agent(agent_name)
    if agent is None:
        return False

    candidates = _settings_candidates(agent, cwd)
    settings_path, existing = _find_settings_with_staso_hooks(candidates)
    if settings_path is None:
        return False

    current_python = sys.executable
    changed = False
    hooks = existing.get("hooks", {})

    for event_entries in hooks.values():
        for entry in event_entries:
            if not _is_staso_hook(entry):
                continue
            for h in entry.get("hooks", [entry]):
                cmd = h.get("command", "")
                match = _PYTHON_PATH_RE.search(cmd)
                if match and match.group(1) != current_python:
                    h["command"] = cmd.replace(match.group(1), current_python)
                    changed = True

    if changed:
        try:
            settings_path.write_text(json.dumps(existing, indent=2), encoding="utf-8")
        except OSError:
            return False
    return changed
