"""
Hooks Configuration

Central configuration for all hook-related paths and settings.
Supports both global (~/.codecontext) and project-local (./.codecontext) installations.
"""

import json
import os
import sys
from pathlib import Path
from typing import Optional, Tuple


# ============== INSTALLATION MODE DETECTION ==============

def detect_install_mode() -> Tuple[str, Optional[Path]]:
    """
    Detect installation mode using marker file (PRIMARY) with path-based fallback.

    Detection order:
    1. Check for marker file at {cwd}/.codecontext/.codecontext_mode (project mode)
    2. Check for marker file at ~/.codecontext/.codecontext_mode (global mode)
    3. Fallback: path-based detection (legacy support)

    Returns:
        Tuple of (mode, project_path) where:
        - mode: "global" or "project"
        - project_path: Path to project (for project mode) or None (for global)
    """
    cwd = Path.cwd()

    # Priority 1: Project marker file (check cwd first)
    project_marker = cwd / ".codecontext" / ".codecontext_mode"
    if project_marker.exists():
        try:
            data = json.loads(project_marker.read_text(encoding="utf-8"))
            if data.get("mode") == "project":
                return ("project", cwd)
        except (json.JSONDecodeError, IOError):
            pass

    # Priority 2: Global marker file
    global_marker = Path.home() / ".codecontext" / ".codecontext_mode"
    if global_marker.exists():
        try:
            data = json.loads(global_marker.read_text(encoding="utf-8"))
            if data.get("mode") == "global":
                return ("global", None)
        except (json.JSONDecodeError, IOError):
            pass

    # Fallback: Path-based detection (for upgrades from pre-marker versions)
    hook_path = Path(__file__).parent
    if hook_path.name == "codecontext" and hook_path.parent.name == "hooks":
        claude_dir = hook_path.parent.parent
        if claude_dir.name == ".claude":
            # Check if this is under a project (not home)
            if claude_dir.parent != Path.home():
                return ("project", claude_dir.parent)

    # Default to global mode
    return ("global", None)


def get_data_root() -> Path:
    """
    Get the data root directory based on installation mode.

    Returns:
        - Project mode: {project}/.codecontext/
        - Global mode: ~/.codecontext/
    """
    mode, project_path = detect_install_mode()
    if mode == "project" and project_path:
        return project_path / ".codecontext"
    return Path.home() / ".codecontext"


# ============== PATH UTILITIES (Inline to avoid import issues) ==============

def encode_project_path(path: str) -> str:
    """
    Encode project path to create safe directory names.

    Example: C:\\Users\\Sam\\my-app -> C--Users-Sam-my-app
    """
    # Skip if already encoded (no path separators)
    if "\\" not in path and "/" not in path and (len(path) <= 1 or path[1] != ":"):
        return path

    # Normalize and encode
    resolved = str(Path(path).resolve())
    return resolved.replace("\\", "-").replace("/", "-").replace(":", "-")


def get_project_dir(project_path: str) -> Path:
    """
    Get/create project directory for a given project path.

    For global mode: ~/.codecontext/projects/{encoded-path}/
    For project mode: {project}/.codecontext/projects/{encoded-path}/
    """
    data_root = get_data_root()
    encoded = encode_project_path(project_path)
    project_dir = data_root / "projects" / encoded
    project_dir.mkdir(parents=True, exist_ok=True)

    # Save original path metadata
    metadata_file = project_dir / ".metadata.json"
    if "\\" in project_path or "/" in project_path:
        if not metadata_file.exists():
            try:
                metadata = {
                    "original_path": str(Path(project_path).resolve()),
                    "encoded_name": encoded
                }
                metadata_file.write_text(json.dumps(metadata, indent=2), encoding="utf-8")
            except IOError:
                pass

    return project_dir


# ============== DIRECTORY CONSTANTS ==============

# These are computed lazily to support mode detection
def _get_codecontext_root() -> Path:
    return get_data_root()


def _get_projects_dir() -> Path:
    return get_data_root() / "projects"


# For backward compatibility, expose as properties that compute on access
class _LazyPaths:
    @property
    def CODECONTEXT_ROOT(self) -> Path:
        return get_data_root()

    @property
    def PROJECTS_DIR(self) -> Path:
        return get_data_root() / "projects"

    @property
    def TEMP_DIR(self) -> Path:
        return get_data_root() / "temp"

_paths = _LazyPaths()

# Export for compatibility (these will be evaluated when accessed)
CODECONTEXT_ROOT = Path.home() / ".codecontext"  # Default fallback
PROJECTS_DIR = CODECONTEXT_ROOT / "projects"
TEMP_DIR = CODECONTEXT_ROOT / "temp"

# Legacy directories (for backward compatibility with queue)
AUTOCODER_DIR = Path.home() / ".autocoder"
MEMORY_DIR = AUTOCODER_DIR / "memory"

# CodeContext Server Configuration
DEFAULT_CODECONTEXT_HOST = "localhost"
DEFAULT_CODECONTEXT_PORT = 8765

# Claude Code directories (source of temp files)
CLAUDE_DIR_NAME = ".claude"
CLAUDE_LOGS_SUBDIR = "logs"

# Temp files to clean up (relative to .claude/logs/)
TEMP_FILES_TO_CLEAN = [
    "session_metrics.log",
    "latest_transcript_entry.json",
]

# Cleanup settings
KEEP_LAST_N_LOG_LINES = 0  # Set to > 0 to preserve recent log entries
CLEANUP_ON_STOP = True     # Whether to clean temp files on Stop hook

# Queue for failed memory submissions (resilient queue system)
QUEUE_FILE = MEMORY_DIR / "pending_queue.jsonl"
QUEUE_LOCK = MEMORY_DIR / "pending_queue.lock"

# Summary Injection Settings
SUMMARY_ENABLED = True           # Whether to inject summaries at session start
SUMMARY_GENERATE_ON_END = True   # Whether to generate summaries at session end
SUMMARY_MODEL = "haiku"          # Model for summary generation


# ============== HELPER FUNCTIONS ==============

def get_project_claude_logs_dir(project_path: str) -> Path:
    """Get the .claude/logs directory for a project."""
    return Path(project_path) / CLAUDE_DIR_NAME / CLAUDE_LOGS_SUBDIR


def get_project_memory_dir(project_path: str) -> Path:
    """Get the memory directory for a specific project (uses encoded path)."""
    if not project_path:
        return get_data_root() / "projects" / "default"
    return get_project_dir(project_path)


def ensure_directories():
    """Create all required directories if they don't exist."""
    data_root = get_data_root()
    data_root.mkdir(parents=True, exist_ok=True)
    (data_root / "projects").mkdir(parents=True, exist_ok=True)
    (data_root / "temp").mkdir(parents=True, exist_ok=True)
    # Legacy directory for queue (backward compatibility)
    MEMORY_DIR.mkdir(parents=True, exist_ok=True)


def get_codecontext_url() -> str:
    """
    Get the CodeContext server URL from environment or defaults.

    Environment variables:
        CODECONTEXT_HOST: Server host (default: localhost)
        CODECONTEXT_PORT: Server port (default: 8765)

    Returns:
        Full URL like "http://localhost:8765"
    """
    host = os.environ.get("CODECONTEXT_HOST", DEFAULT_CODECONTEXT_HOST)
    port = os.environ.get("CODECONTEXT_PORT", str(DEFAULT_CODECONTEXT_PORT))
    return f"http://{host}:{port}"


def extract_project_name(cwd: str) -> str:
    """
    Extract encoded project name from working directory path.

    Encodes the full path to create a unique, collision-free project identifier.
    Example: C:\\Users\\Sam\\my-app -> C--Users-Sam-my-app

    Args:
        cwd: Current working directory path

    Returns:
        Encoded project name or empty string if invalid
    """
    if not cwd:
        return ""
    return encode_project_path(cwd)


# Ensure directories exist on import
ensure_directories()
