"""Logging utilities for scry-run.

Provides detailed file-based logging for debugging generation issues.
"""

import datetime
import os
import sys
import traceback
from pathlib import Path
from typing import Optional


class ScryRunLogger:
    """Logger that writes detailed debug info to a file.

    Log file is created in:
    1. The app's logs/ directory (if running in an app context)
    2. Directory specified by SCRY_LOG_DIR
    3. ~/.scry-run/logs/ (fallback for CLI commands)
    """

    _instance: Optional["ScryRunLogger"] = None

    def __init__(self, log_dir: Optional[Path] = None):
        """Initialize logger.

        Args:
            log_dir: Directory for log file. If None, uses auto-detection.
        """
        self._log_dir: Optional[Path] = None
        self._log_file: Optional[Path] = None
        # Session timestamp for unique log files per run
        self._session_id = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")

        if log_dir:
            self._log_dir = log_dir
        else:
            env_dir = os.environ.get("SCRY_LOG_DIR")
            if env_dir:
                self._log_dir = Path(env_dir)

        # Debug logging is ON by default. Set SCRY_DEBUG=0 to disable.
        debug_env = os.environ.get("SCRY_DEBUG", "").lower()
        self._enabled = debug_env not in ("0", "false", "no", "off")

    @property
    def log_dir(self) -> Path:
        """Get log directory, with fallback to ~/.scry-run/logs/."""
        if self._log_dir:
            return self._log_dir
        # Fallback to global scry-run logs directory (not cwd)
        fallback = Path.home() / ".scry-run" / "logs"
        fallback.mkdir(parents=True, exist_ok=True)
        return fallback
    
    @property  
    def log_file(self) -> Path:
        """Get log file path (unique per session)."""
        if self._log_file:
            return self._log_file
        return self.log_dir / f"generation_{self._session_id}.log"
    
    def set_log_dir(self, log_dir: Path):
        """Set the log directory to use.
        
        Args:
            log_dir: Directory for log files
        """
        self._log_dir = log_dir
        self._log_file = log_dir / f"generation_{self._session_id}.log"
        # Ensure directory exists
        log_dir.mkdir(parents=True, exist_ok=True)
    
    def set_app_context(self, app_dir: Path):
        """Set logging to use an app's logs/ directory.
        
        Args:
            app_dir: The app's root directory (containing logs/)
        """
        logs_dir = app_dir / "logs"
        logs_dir.mkdir(parents=True, exist_ok=True)
        self.set_log_dir(logs_dir)
    
    @classmethod
    def get(cls) -> "ScryRunLogger":
        """Get singleton logger instance."""
        if cls._instance is None:
            cls._instance = cls()
        return cls._instance
    
    def enable(self):
        """Enable logging."""
        self._enabled = True
    
    def disable(self):
        """Disable logging."""
        self._enabled = False
    
    def _write(self, level: str, message: str, details: Optional[str] = None):
        """Write a log entry to file.
        
        Args:
            level: Log level (DEBUG, INFO, WARN, ERROR)
            message: Main log message
            details: Optional detailed content (e.g., full response text)
        """
        if not self._enabled:
            return
        
        timestamp = datetime.datetime.now().isoformat()
        
        try:
            with open(self.log_file, "a", encoding="utf-8") as f:
                f.write(f"\n{'='*80}\n")
                f.write(f"[{timestamp}] [{level}] {message}\n")
                if details:
                    f.write(f"{'-'*40}\n")
                    f.write(details)
                    if not details.endswith("\n"):
                        f.write("\n")
        except Exception as e:
            # Don't let logging errors break the main flow
            print(f"[scry-run] Warning: Could not write to log file: {e}", file=sys.stderr)
    
    def debug(self, message: str, details: Optional[str] = None):
        """Log debug message."""
        self._write("DEBUG", message, details)
    
    def info(self, message: str, details: Optional[str] = None):
        """Log info message."""
        self._write("INFO", message, details)
    
    def warn(self, message: str, details: Optional[str] = None):
        """Log warning message."""
        self._write("WARN", message, details)
    
    def error(self, message: str, details: Optional[str] = None):
        """Log error message."""
        self._write("ERROR", message, details)
    
    def log_generation_start(self, class_name: str, attr_name: str, prompt: str):
        """Log the start of a generation request."""
        self.info(
            f"Generation started: {class_name}.{attr_name}",
            f"PROMPT:\n{prompt}"
        )
    
    def log_generation_response(self, response_text: str):
        """Log the raw LLM response."""
        self.debug(
            "LLM Response received",
            f"RESPONSE:\n{response_text}"
        )
    
    def log_validation_error(self, error: Exception, code: Optional[str] = None):
        """Log a validation error with full details."""
        details = f"ERROR: {error}\n\nTRACEBACK:\n{traceback.format_exc()}"
        if code:
            details += f"\n\nGENERATED CODE:\n{code}"
        self.error("Validation failed", details)
    
    def log_generation_success(self, class_name: str, attr_name: str, code: str):
        """Log successful generation."""
        self.info(
            f"Generation succeeded: {class_name}.{attr_name}",
            f"GENERATED CODE:\n{code}"
        )


# Convenience function
def get_logger() -> ScryRunLogger:
    """Get the global logger instance."""
    return ScryRunLogger.get()
