"""
Log management tools for the Nova Act MCP Server.

This module provides functionality for viewing and compressing HTML log files
produced by Nova Act during browser sessions.
"""

import base64
import glob
import gzip
import json
import os
import time
from pathlib import Path
from typing import Dict, List, Any, Optional

from .. import mcp
from ..config import log, log_error, initialize_environment
from ..session_manager import active_sessions, session_lock
from ..utils import compress_log_file, _normalize_logs_dir

@mcp.tool(
    name="view_html_log",
    description="Retrieves and displays HTML log files generated by Nova Act browser sessions. These logs contain detailed information about browser interactions, including screenshots and executed actions. Provide either a session_id to automatically find the most recent HTML log for that session, or html_path to directly specify a log file path."
)
async def view_html_log(
    session_id: Optional[str] = None,
    html_path: Optional[str] = None
) -> Dict[str, Any]:
    """
    Retrieves and displays the HTML log file for a browser session.
    
    Nova Act generates detailed HTML logs for each browser automation session, which
    include screenshots, executed actions, and debugging information. This tool
    makes these logs accessible for analysis and debugging. You can access logs
    either by specifying a session ID (to get the most recent log for that session)
    or by providing a direct path to a log file.
    
    Args:
        session_id: The ID of the browser session to view logs for. If provided,
                   the tool will search for the most recent HTML log file in this
                   session's logs directory. Either this or html_path must be provided.
        html_path: Direct path to an HTML log file. Use this when you already know
                  the exact path to the log file you want to view. Either this or
                  session_id must be provided.
        
    Returns:
        A dictionary containing:
        - content (List[Dict]): Structured content for rendering, with type "html"
                               containing the HTML content of the log file.
        - file_path (str): The absolute path to the HTML log file.
        - file_size (int): Size of the file in bytes.
        - file_size_formatted (str): Human-readable file size (e.g., "123.4 KB").
        - timestamp (float): Unix timestamp of when the log file was last modified.
        - timestamp_formatted (str): Human-readable timestamp.
        - error (Optional[Dict]): Error information if the log file could not be retrieved.
    """
    initialize_environment()
    
    if not session_id and not html_path:
        return {
            "error": {
                "message": "Missing required parameter: session_id or html_path",
                "code": "MISSING_PARAMETER"
            }
        }
    
    # If session ID is provided, try to find the logs directory
    logs_dir = None
    if session_id:
        with session_lock:
            session_data = active_sessions.get(session_id)
            if session_data:
                nova_instance = session_data.get("nova_instance")
                if nova_instance:
                    logs_dir = _normalize_logs_dir(nova_instance)
        
        if not logs_dir and not html_path:
            return {
                "error": {
                    "message": f"Session {session_id} not found or has no logs directory",
                    "code": "SESSION_NOT_FOUND"
                }
            }
    
    # If html_path is provided directly, use it
    if html_path:
        if os.path.isfile(html_path):
            html_file_path = html_path
        else:
            return {
                "error": {
                    "message": f"File not found: {html_path}",
                    "code": "FILE_NOT_FOUND"
                }
            }
    else:
        # Try to find the HTML log file in the logs directory
        html_files = []
        for ext in [".html", ".htm"]:
            html_files.extend(glob.glob(os.path.join(logs_dir, f"*{ext}")))
        
        if not html_files:
            return {
                "error": {
                    "message": f"No HTML log files found for session {session_id}",
                    "code": "NO_LOGS_FOUND"
                }
            }
        
        # Sort by modification time to get the most recent
        html_files.sort(key=os.path.getmtime, reverse=True)
        html_file_path = html_files[0]
    
    try:
        # Read the HTML file
        with open(html_file_path, "r", encoding="utf-8", errors="ignore") as f:
            html_content = f.read()
        
        # Get file info
        file_size = os.path.getsize(html_file_path)
        file_mtime = os.path.getmtime(html_file_path)
        
        # Return content as a structured object for proper display in FastMCP
        content = [{
            "type": "html",
            "html": html_content
        }]
        
        # Prepare result
        result = {
            "content": content,
            "file_path": html_file_path,
            "file_size": file_size,
            "file_size_formatted": f"{file_size / 1024:.1f} KB",
            "timestamp": file_mtime,
            "timestamp_formatted": time.strftime(
                "%Y-%m-%d %H:%M:%S", time.localtime(file_mtime)
            ),
        }
        
        log(f"Returned HTML log: {html_file_path} ({result['file_size_formatted']})")
        return result
    
    except Exception as e:
        log_error(f"Error reading HTML log file: {str(e)}")
        return {
            "error": {
                "message": f"Error reading HTML log file: {str(e)}",
                "code": "READ_ERROR"
            }
        }

@mcp.tool(
    name="compress_logs",
    description="Compresses Nova Act log files to reduce size while preserving important information. Optionally extracts embedded screenshots to a separate directory before compression. Use this tool to prepare logs for storage or transmission when they become too large for efficient handling."
)
async def compress_logs(
    log_path: str,
    extract_screenshots: bool = True,
    compression_level: int = 9
) -> Dict[str, Any]:
    """
    Compresses a Nova Act log file by optionally extracting screenshots and applying gzip compression.
    
    This tool helps manage the size of Nova Act log files, which can become quite large
    due to embedded screenshots and detailed interaction records. The compression process
    can optionally extract screenshots to a separate directory (maintaining references to them)
    before applying gzip compression to the JSON log data.
    
    Args:
        log_path: The absolute path to the log file to compress. This should be a path
                 to a JSON log file generated by Nova Act (not an HTML log file).
        extract_screenshots: If True (default), embedded screenshots in the log file will
                            be extracted to a separate directory before compression, reducing
                            file size significantly while preserving the images.
        compression_level: Gzip compression level (1-9). Higher values provide better
                          compression but take longer to process. Default is 9 (maximum).
        
    Returns:
        A dictionary containing:
        - original_path (str): The original path to the uncompressed log file.
        - compressed_path (str): The path to the new compressed log file (.gz extension).
        - original_size (int): Size of the original file in bytes.
        - compressed_size (int): Size of the compressed file in bytes.
        - compression_ratio (float): The compression ratio achieved (original/compressed).
        - screenshots_dir (Optional[str]): Directory where screenshots were extracted, if any.
        - screenshots_count (Optional[int]): Number of screenshots extracted, if any.
        - screenshots_size (Optional[int]): Total size of extracted screenshots in bytes, if any.
        - success (bool): True if compression was successful.
        - timestamp (float): Unix timestamp of when the compression was performed.
        - error (Optional[Dict]): Error information if compression failed.
    """
    initialize_environment()
    
    if not log_path:
        return {
            "error": {
                "message": "Missing required parameter: log_path",
                "code": "MISSING_PARAMETER"
            }
        }
    
    # Normalize path
    log_path = os.path.abspath(os.path.expanduser(log_path))
    
    # Check if the file exists
    if not os.path.isfile(log_path):
        return {
            "error": {
                "message": f"Log file not found: {log_path}",
                "code": "FILE_NOT_FOUND"
            }
        }
    
    # Compress the log file
    result = compress_log_file(log_path, extract_screenshots=extract_screenshots, compression_level=compression_level)
    
    # Add a timestamp
    result["timestamp"] = time.time()
    
    return result

@mcp.tool(
    name="view_compressed_log",
    description="Retrieves and displays the contents of a compressed log file (.gz) previously created by the compress_logs tool. Automatically decompresses the file and attempts to parse it as JSON. Use this tool to examine logs that have been compressed for storage efficiency."
)
async def view_compressed_log(
    compressed_path: str
) -> Dict[str, Any]:
    """
    Views the contents of a compressed log file, decompressing and parsing it as JSON if possible.
    
    This tool allows you to examine the contents of log files that have been compressed
    with the compress_logs tool. It handles both gzipped (.gz) files and regular files,
    and attempts to parse the content as JSON for structured viewing. If the content is
    not valid JSON, it will be returned as plain text.
    
    Args:
        compressed_path: The absolute path to the compressed log file. Typically this is
                        a .gz file created by the compress_logs tool, but the tool will
                        also handle non-compressed files.
        
    Returns:
        A dictionary containing:
        - content (List[Dict]): Structured content for rendering. If the content was
                               successfully parsed as JSON, this will be a formatted
                               JSON code block. Otherwise, it will be plain text.
        - compressed_path (str): The path to the compressed file.
        - record_count (Optional[int]): Number of records in the JSON data, if applicable.
        - parsed_json (bool): Whether the content was successfully parsed as JSON.
        - success (bool): True if the file was successfully retrieved and decompressed.
        - error (Optional[Dict]): Error information if the file could not be processed.
    """
    initialize_environment()
    
    if not compressed_path:
        return {
            "error": {
                "message": "Missing required parameter: compressed_path",
                "code": "MISSING_PARAMETER"
            }
        }
    
    # Normalize path
    compressed_path = os.path.abspath(os.path.expanduser(compressed_path))
    
    # Check if the file exists
    if not os.path.isfile(compressed_path):
        return {
            "error": {
                "message": f"Compressed log file not found: {compressed_path}",
                "code": "FILE_NOT_FOUND"
            }
        }
    
    try:
        # Check if it's a gzip file
        if compressed_path.endswith(".gz"):
            with gzip.open(compressed_path, "rb") as f:
                decompressed_data = f.read().decode("utf-8")
            
            # Try to parse the JSON
            try:
                json_data = json.loads(decompressed_data)
                log(f"Successfully parsed JSON from compressed file ({len(json_data)} records)")
                
                # Prepare result with structured content
                content = [{
                    "type": "code",
                    "language": "json",
                    "code": json.dumps(json_data, indent=2)
                }]
                
                result = {
                    "success": True,
                    "content": content,
                    "compressed_path": compressed_path,
                    "record_count": len(json_data),
                    "parsed_json": True,
                }
                
                return result
            
            except json.JSONDecodeError:
                # Not valid JSON, just return the raw content
                content = [{
                    "type": "text",
                    "text": decompressed_data
                }]
                
                return {
                    "success": True,
                    "content": content,
                    "compressed_path": compressed_path,
                    "parsed_json": False,
                }
        
        else:
            # Not a gzip file, just read it normally
            with open(compressed_path, "r", encoding="utf-8") as f:
                content_data = f.read()
            
            # Try to parse JSON
            try:
                json_data = json.loads(content_data)
                log(f"Successfully parsed JSON from file ({len(json_data)} records)")
                
                # Prepare result with structured content
                content = [{
                    "type": "code",
                    "language": "json",
                    "code": json.dumps(json_data, indent=2)
                }]
                
                result = {
                    "success": True,
                    "content": content,
                    "file_path": compressed_path,
                    "record_count": len(json_data),
                    "parsed_json": True,
                }
                
                return result
            
            except json.JSONDecodeError:
                # Not valid JSON, just return the raw content
                content = [{
                    "type": "text",
                    "text": content_data
                }]
                
                return {
                    "success": True,
                    "content": content,
                    "file_path": compressed_path,
                    "parsed_json": False,
                }
    
    except Exception as e:
        log_error(f"Error reading compressed log file: {str(e)}")
        return {
            "error": {
                "message": f"Error reading compressed log file: {str(e)}",
                "code": "READ_ERROR"
            }
        }