#!/usr/bin/env python3
"""
SessionEnd Hook - Runs consolidation scan and generates summary.

This hook is designed to be called by Claude Code's hook system when
a session ends. It:
1. Runs consolidation scan to clean up duplicates
2. Generates an updated project summary (if new memories were added)

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

import os
import sys
import json

# 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:
    print("[SessionEnd] Warning: requests module not available, skipping")
    sys.exit(0)

from config import get_codecontext_url, extract_project_name, SUMMARY_GENERATE_ON_END
from server_state import ServerState, shutdown_server


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

    Returns True if scan was successful.
    """
    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:
                print(f"[SessionEnd] Consolidated {result['clusters_found']} clusters in {project}")
                if result.get("deleted", 0) > 0:
                    print(f"[SessionEnd] Deleted {result['deleted']} duplicate memories")
            elif result.get("scanned"):
                print(f"[SessionEnd] No cleanup needed for {project}")
            else:
                message = result.get("message", "Unknown status")
                print(f"[SessionEnd] {message}")
            return True
        else:
            print(f"[SessionEnd] Server returned {response.status_code}")
            return False

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


def generate_summary(base_url: str, project: str):
    """
    Generate an updated project summary.

    Only generates if there are new memories since last summary.
    """
    try:
        response = requests.post(
            f"{base_url}/api/summary/regenerate",
            params={
                "project": project,
                "force_full": False  # Incremental update
            },
            timeout=180  # 3 minute timeout for summary generation
        )

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

            if result.get("success"):
                version = result.get("version", "?")
                new_count = result.get("new_memories_count", 0)
                print(f"[SessionEnd] Summary v{version} generated ({new_count} new memories)")
            else:
                # No new memories or generation skipped
                message = result.get("message", "")
                if "No new memories" in message:
                    print(f"[SessionEnd] No new memories, summary unchanged")
                else:
                    print(f"[SessionEnd] Summary skipped: {message}")
        else:
            print(f"[SessionEnd] Summary generation returned {response.status_code}")

    except requests.exceptions.ConnectionError:
        # Server not running - silent skip
        pass
    except requests.exceptions.Timeout:
        print("[SessionEnd] Summary generation timed out")
    except Exception as e:
        print(f"[SessionEnd] Summary error: {e}")


def unregister_session_and_maybe_stop_server(session_id: str = ""):
    """
    Unregister this session and stop server if no active sessions remain.

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

    This ensures the server doesn't run indefinitely when all sessions end.
    """

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

    # Unregister this session
    if session_id:
        state.unregister_session(session_id)

    # Clean up any stale sessions (from crashed terminals, etc.)
    stale_count = state.cleanup_stale_sessions(max_age_hours=24)
    if stale_count > 0:
        print(f"[SessionEnd] Cleaned up {stale_count} stale session(s)")

    # Check if server should be stopped
    if state.get_active_count() == 0 and state.is_server_running():
        print("[SessionEnd] No active sessions, stopping server...")
        if shutdown_server(state.server_pid):
            state.server_pid = None
            state.started_at = None
            print("[SessionEnd] Server stopped")
        else:
            print("[SessionEnd] Warning: Failed to stop server cleanly")

    # Save updated state
    state.save()


def on_session_end():
    """Called when Claude Code session ends."""
    # 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", "")

    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:
            print("[SessionEnd] No project detected, skipping")
            # Still unregister session and potentially stop server
            unregister_session_and_maybe_stop_server(session_id)
            return

        base_url = get_codecontext_url()

        # No health check - just try the API calls directly
        # If server isn't running, the calls fail gracefully

        # Step 1: Run consolidation scan
        run_consolidation_scan(base_url, project)

        # Step 2: Generate summary (if enabled)
        if SUMMARY_GENERATE_ON_END:
            generate_summary(base_url, project)

        # Step 3: Unregister session and potentially stop server
        unregister_session_and_maybe_stop_server(session_id)

    except Exception as e:
        print(f"[SessionEnd] Error: {e}")
        # Still try to unregister session even on error
        try:
            unregister_session_and_maybe_stop_server(session_id)
        except:
            pass


if __name__ == "__main__":
    on_session_end()
