#!/usr/bin/env python3
"""
SessionStart Hook - Injects summary context and runs consolidation scan.

This hook is designed to be called by Claude Code's hook system when
a new session begins. It:
1. Injects the project summary and recent timeline
2. Runs consolidation scan to clean up duplicates

Hook Configuration (add to ~/.claude/settings.json):
{
  "hooks": {
    "SessionStart": [
      {
        "type": "command",
        "command": "python C:/Users/SamUser/my_builds/claude-desktop/agentic-coder/hooks/session_start.py"
      }
    ]
  }
}
"""

import os
import sys
import json
from datetime import datetime

# Skip if this is a CodeContext subprocess (prevents recursive hooks)
if os.environ.get("CODECONTEXT_SUBPROCESS") == "1":
    sys.exit(0)

# Add parent directory to path for imports
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent))

try:
    import requests
except ImportError:
    # Output JSON error message
    output = {"systemMessage": "Warning: requests module not available, skipping"}
    print(json.dumps(output))
    sys.exit(0)

from config import get_codecontext_url, extract_project_name, SUMMARY_ENABLED
from server_state import (
    ServerState,
    start_server_background,
    wait_for_server_health
)

# Add codecontext to path for imports (hooks/ is inside codecontext/)
sys.path.insert(0, str(Path(__file__).parent.parent))
from cli_utils import get_display_name


def get_summary_injection(base_url: str, project: str) -> dict:
    """
    Get project summary and timeline for injection.

    Returns:
        Dict with injection text and metadata for status messages.
    """
    try:
        # Get summary injection text (longer timeout for server startup)
        response = requests.get(
            f"{base_url}/api/summary/injection",
            params={"project": project},
            timeout=60
        )

        if response.status_code != 200:
            return {
                "injection": "",
                "token_estimate": 0,
                "has_summary": False,
                "version": 0,
                "memory_count": 0,
                "error": None
            }

        data = response.json()
        return {
            "injection": data.get("injection", ""),
            "token_estimate": data.get("token_estimate", 0),
            "has_summary": data.get("has_summary", False),
            "version": data.get("version", 0),
            "memory_count": data.get("memory_count", 0),
            "error": None
        }

    except requests.exceptions.ConnectionError:
        # Server not running - silent skip
        return {
            "injection": "",
            "token_estimate": 0,
            "has_summary": False,
            "version": 0,
            "memory_count": 0,
            "error": None
        }
    except requests.exceptions.Timeout:
        return {
            "injection": "",
            "token_estimate": 0,
            "has_summary": False,
            "version": 0,
            "memory_count": 0,
            "error": "Summary injection timed out"
        }
    except Exception as e:
        return {
            "injection": "",
            "token_estimate": 0,
            "has_summary": False,
            "version": 0,
            "memory_count": 0,
            "error": f"Summary error: {e}"
        }


def run_consolidation_scan(base_url: str, project: str) -> str:
    """
    Run consolidation scan to clean up duplicates.

    Returns status message (empty string if silent).
    """
    try:
        response = requests.post(
            f"{base_url}/api/consolidation/auto-scan",
            params={
                "project": project,
                "resolve": True
            },
            timeout=300  # 5 minute timeout for full consolidation
        )

        if response.status_code == 200:
            result = response.json()

            if result.get("clusters_found", 0) > 0:
                msg = f"cleaned {result['clusters_found']} duplicates"
                if result.get("deleted", 0) > 0:
                    msg += f" ({result['deleted']} removed)"
                return msg
            elif result.get("scanned"):
                return ""  # Clean state - no need to report
            else:
                return result.get("message", "")
        else:
            return ""  # Silent on errors

    except requests.exceptions.ConnectionError:
        # Server not running - silent skip
        return ""
    except requests.exceptions.Timeout:
        return "Scan timed out (server may still be processing)"
    except Exception as e:
        return f"Consolidation error: {e}"


def ensure_server_and_register_session(session_id: str = "") -> dict:
    """
    Ensure server is running and register this session.

    Args:
        session_id: Session ID to register (from stdin JSON)

    Returns:
        Dict with server state info:
        - success: True if server is ready
        - server_started: True if we started the server, False if already running
        - session_registered: True if session was registered
        - error: Error message if failed
    """
    base_url = get_codecontext_url()

    # Load current server state
    state = ServerState.load()

    # Check if server is actually running
    server_alive = False
    server_started = False
    if state.server_pid and state.is_server_running():
        # Verify with health check
        try:
            response = requests.get(f"{base_url}/health", timeout=2)
            server_alive = response.status_code == 200
        except:
            server_alive = False

    # Start server if not running
    if not server_alive:
        try:
            pid = start_server_background()
            state.server_pid = pid
            state.started_at = datetime.utcnow().isoformat() + "Z"
            server_started = True

            # Wait for server to become healthy (model loading takes time)
            if not wait_for_server_health(base_url, timeout=60):
                # Server didn't start in time - clear state
                state.server_pid = None
                state.started_at = None
                state.save()
                return {
                    "success": False,
                    "server_started": True,
                    "session_registered": False,
                    "error": "Server failed to start (timeout)"
                }

        except Exception as e:
            # Server start failed
            return {
                "success": False,
                "server_started": False,
                "session_registered": False,
                "error": f"Server start failed: {e}"
            }

    # Register this session
    session_registered = False
    if session_id:
        state.register_session(session_id)
        session_registered = True

    # Save updated state
    state.save()
    return {
        "success": True,
        "server_started": server_started,
        "session_registered": session_registered,
        "error": None
    }


def build_status_message(
    server_status: dict,
    summary_status: dict,
    consolidation_msg: str
) -> str:
    """
    Build descriptive status message from collected state.

    Args:
        server_status: Dict from ensure_server_and_register_session()
        summary_status: Dict from get_summary_injection()
        consolidation_msg: Message from run_consolidation_scan()

    Returns:
        Formatted status message for the user.
    """
    if not server_status["success"]:
        error = server_status.get("error", "Server failed to start")
        return f"CodeContext: ⚠ Degraded | {error}"

    parts = []

    # Server info
    if server_status["server_started"]:
        parts.append("Server started")
    else:
        parts.append("Server running")

    # Memory/Summary info
    memory_count = summary_status.get("memory_count", 0)
    has_summary = summary_status.get("has_summary", False)

    if memory_count == 0:
        parts.append("No memories yet")
    elif has_summary:
        version = summary_status.get("version", 0)
        tokens = summary_status.get("token_estimate", 0)
        token_str = f"~{tokens // 1000}k tokens" if tokens >= 1000 else f"~{tokens} tokens"
        parts.append(f"{memory_count} memories")
        parts.append(f"Summary v{version} ({token_str})")
    else:
        parts.append(f"{memory_count} memories")
        parts.append("No summary yet")

    # Consolidation info
    if consolidation_msg:
        parts.append(consolidation_msg.capitalize())

    # Session registration
    if server_status.get("session_registered"):
        parts.append("Session registered")

    # Add server UI URL
    base_url = get_codecontext_url()

    return "CodeContext: ✓ Ready | " + " | ".join(parts) + f" | UI: {base_url}"


def on_session_start():
    """Called when Claude Code session starts."""
    # Read stdin event data ONCE at the start (can only read once)
    event_data = {}
    if not sys.stdin.isatty():
        try:
            event_data = json.load(sys.stdin)
        except (json.JSONDecodeError, EOFError):
            pass

    # Extract session_id from event data
    session_id = event_data.get("session_id", "")

    # Step 0: Ensure server is running and register this session
    server_status = ensure_server_and_register_session(session_id)
    if not server_status["success"]:
        # Server couldn't start - emit degraded message
        status_msg = build_status_message(server_status, {}, "")
        output = {"systemMessage": status_msg}
        print(json.dumps(output))
        return

    try:
        # Get project directory - env var (set by Claude) or cwd from stdin event
        # Note: CLAUDE_PROJECT_DIR is only in env var, not stdin (see docs/claude-hook-event-data.md)
        project_dir = (
            os.environ.get("CLAUDE_PROJECT_DIR") or
            event_data.get("cwd") or
            str(Path.cwd())
        )

        project = extract_project_name(project_dir)

        if not project:
            output = {"systemMessage": "CodeContext: No project detected, skipping"}
            print(json.dumps(output))
            return

        base_url = get_codecontext_url()

        # Step 1: Get summary injection (if enabled)
        summary_status = {}
        additional_context = ""
        if SUMMARY_ENABLED:
            summary_status = get_summary_injection(base_url, project)
            if summary_status.get("injection"):
                additional_context = summary_status["injection"]

        # Step 2: Run consolidation scan
        consolidation_msg = run_consolidation_scan(base_url, project)

        # Build descriptive status message
        status_msg = build_status_message(server_status, summary_status, consolidation_msg)

        # Build final output JSON - always output a message now
        output = {"systemMessage": status_msg}

        # Add context injection if we have summary content
        if additional_context:
            output["hookSpecificOutput"] = {
                "hookEventName": "SessionStart",
                "additionalContext": additional_context
            }

        print(json.dumps(output))

    except Exception as e:
        output = {"systemMessage": f"CodeContext: Error - {e}"}
        print(json.dumps(output))


if __name__ == "__main__":
    on_session_start()
