"""
System Operations Handler

Manages WordPress system operations including:
- System information (PHP, MySQL, WordPress versions)
- Disk usage statistics
- Cron job management
- Cache operations
- Error log retrieval

Most operations require WP-CLI for advanced functionality.
"""

import json
import re
from typing import Any

from plugins.wordpress.client import WordPressClient
from plugins.wordpress.wp_cli import WPCLIManager


def get_tool_specifications() -> list[dict[str, Any]]:
    """Return tool specifications for ToolGenerator"""
    return [
        # System Info
        {
            "name": "system_info",
            "method_name": "system_info",
            "description": "Get comprehensive system information including PHP version, MySQL version, WordPress version, server info, memory limits, and more.",
            "schema": {"type": "object", "properties": {}},
            "scope": "read",
        },
        # PHP Info
        {
            "name": "system_phpinfo",
            "method_name": "system_phpinfo",
            "description": "Get detailed PHP configuration including loaded extensions, ini settings, and disabled functions.",
            "schema": {"type": "object", "properties": {}},
            "scope": "read",
        },
        # Disk Usage
        {
            "name": "system_disk_usage",
            "method_name": "system_disk_usage",
            "description": "Get disk usage statistics including uploads size, plugins size, themes size, and database size.",
            "schema": {"type": "object", "properties": {}},
            "scope": "read",
        },
        # Clear All Caches
        {
            "name": "system_clear_all_caches",
            "method_name": "system_clear_all_caches",
            "description": "Clear all caches including object cache, transients, and opcache (if available). Safe to run anytime.",
            "schema": {"type": "object", "properties": {}},
            "scope": "write",
        },
        # Cron List
        {
            "name": "cron_list",
            "method_name": "cron_list",
            "description": "List all scheduled WordPress cron jobs with schedule, next run time, and arguments.",
            "schema": {"type": "object", "properties": {}},
            "scope": "read",
        },
        # Cron Run
        {
            "name": "cron_run",
            "method_name": "cron_run",
            "description": "Manually trigger a specific cron job by hook name. Useful for testing or forcing scheduled tasks.",
            "schema": {
                "type": "object",
                "properties": {
                    "hook": {"type": "string", "description": "Cron hook name to execute"},
                    "args": {
                        "type": "array",
                        "items": {},
                        "default": [],
                        "description": "Optional arguments to pass to the hook",
                    },
                },
                "required": ["hook"],
            },
            "scope": "write",
        },
        # Error Log
        {
            "name": "error_log",
            "method_name": "error_log",
            "description": "Get recent PHP error log entries. Useful for debugging issues. Admin scope recommended for security.",
            "schema": {
                "type": "object",
                "properties": {
                    "lines": {
                        "type": "integer",
                        "default": 100,
                        "minimum": 1,
                        "maximum": 1000,
                        "description": "Number of log lines to retrieve",
                    },
                    "filter": {
                        "type": "string",
                        "description": "Filter logs by keyword (case-insensitive)",
                    },
                    "level": {
                        "type": "string",
                        "enum": ["error", "warning", "notice", "fatal"],
                        "description": "Filter by error level",
                    },
                },
            },
            "scope": "read",
        },
    ]


class SystemHandler:
    """Handles WordPress system operations"""

    def __init__(self, client: WordPressClient, wp_cli: WPCLIManager | None = None):
        """
        Initialize System Handler

        Args:
            client: WordPress REST API client
            wp_cli: WP-CLI manager (optional, for advanced operations)
        """
        self.client = client
        self.wp_cli = wp_cli
        self.logger = client.logger

    async def wp_cli_version(self) -> dict[str, Any]:
        """Get WP-CLI version information"""
        if not self.wp_cli:
            return {"success": False, "version": None, "error": "WP-CLI not available"}

        try:
            result = await self.wp_cli.execute_command("cli version")
            version_output = result.get("output", "").strip()

            # Parse version (e.g., "WP-CLI 2.10.0")
            version = (
                version_output.replace("WP-CLI ", "").strip()
                if "WP-CLI" in version_output
                else version_output
            )

            return {"success": True, "version": version, "full_output": version_output}

        except Exception as e:
            self.logger.error(f"WP-CLI version check failed: {str(e)}")
            return {"success": False, "version": None, "error": str(e)}

    async def system_info(self) -> dict[str, Any]:
        """Get comprehensive system information"""
        if not self.wp_cli:
            return {
                "success": False,
                "error": "WP-CLI not available. Container name not configured.",
            }

        try:
            # Get various system info using WP-CLI
            info_commands = {
                "php_version": "eval 'echo PHP_VERSION;'",
                "wordpress_version": "core version",
                "site_url": "option get siteurl",
                "active_theme": "theme list --status=active --field=name",
                "plugin_count": "plugin list --status=active --format=count",
                "wp_debug": "config get WP_DEBUG",
                "wp_debug_log": "config get WP_DEBUG_LOG",
                "multisite": "config get MULTISITE",
            }

            results = {}
            for key, cmd in info_commands.items():
                try:
                    result = await self.wp_cli.execute_command(cmd)
                    results[key] = result.get("output", "").strip()
                except Exception as e:
                    self.logger.warning(f"Failed to get {key}: {str(e)}")
                    results[key] = "N/A"

            # Get PHP settings
            php_settings_cmd = """eval 'echo json_encode([
                "memory_limit" => ini_get("memory_limit"),
                "max_execution_time" => ini_get("max_execution_time"),
                "upload_max_filesize" => ini_get("upload_max_filesize"),
                "post_max_size" => ini_get("post_max_size"),
                "max_input_vars" => ini_get("max_input_vars")
            ]);'"""

            php_result = await self.wp_cli.execute_command(php_settings_cmd)
            php_settings = json.loads(php_result.get("output", "{}"))

            # Get MySQL version
            mysql_cmd = 'db query "SELECT VERSION()" --skip-column-names'
            mysql_result = await self.wp_cli.execute_command(mysql_cmd)
            mysql_version = mysql_result.get("output", "N/A").strip()

            # Get server software from environment
            server_cmd = 'eval \'echo $_SERVER["SERVER_SOFTWARE"] ?? "Unknown";\''
            server_result = await self.wp_cli.execute_command(server_cmd)
            server_software = server_result.get("output", "Unknown").strip()

            # Get loaded PHP extensions
            ext_cmd = "eval 'echo json_encode(get_loaded_extensions());'"
            ext_result = await self.wp_cli.execute_command(ext_cmd)
            php_extensions = json.loads(ext_result.get("output", "[]"))

            return {
                "success": True,
                "php_version": results.get("php_version", "N/A"),
                "mysql_version": mysql_version,
                "wordpress_version": results.get("wordpress_version", "N/A"),
                "server_software": server_software,
                "memory_limit": php_settings.get("memory_limit", "N/A"),
                "max_execution_time": int(php_settings.get("max_execution_time", 0)),
                "upload_max_filesize": php_settings.get("upload_max_filesize", "N/A"),
                "post_max_size": php_settings.get("post_max_size", "N/A"),
                "max_input_vars": int(php_settings.get("max_input_vars", 0)),
                "php_extensions": php_extensions,
                "wp_debug": results.get("wp_debug", "false") == "true",
                "wp_debug_log": results.get("wp_debug_log", "false") == "true",
                "multisite": results.get("multisite", "false") == "true",
                "active_plugins": int(results.get("plugin_count", 0)),
                "active_theme": results.get("active_theme", "N/A"),
                "site_url": results.get("site_url", "N/A"),
            }

        except Exception as e:
            self.logger.error(f"System info failed: {str(e)}")
            return {"success": False, "error": str(e)}

    async def system_phpinfo(self) -> dict[str, Any]:
        """Get detailed PHP configuration"""
        if not self.wp_cli:
            return {"success": False, "error": "WP-CLI not available"}

        try:
            # Get PHP version and SAPI
            version_cmd = "eval 'echo PHP_VERSION;'"
            version_result = await self.wp_cli.execute_command(version_cmd)
            php_version = version_result.get("output", "").strip()

            sapi_cmd = "eval 'echo PHP_SAPI;'"
            sapi_result = await self.wp_cli.execute_command(sapi_cmd)
            php_sapi = sapi_result.get("output", "").strip()

            # Get loaded extensions
            ext_cmd = "eval 'echo json_encode(get_loaded_extensions());'"
            ext_result = await self.wp_cli.execute_command(ext_cmd)
            extensions = json.loads(ext_result.get("output", "[]"))

            # Get important ini settings
            ini_settings_cmd = """eval 'echo json_encode([
                "display_errors" => ini_get("display_errors"),
                "error_reporting" => ini_get("error_reporting"),
                "log_errors" => ini_get("log_errors"),
                "error_log" => ini_get("error_log"),
                "memory_limit" => ini_get("memory_limit"),
                "max_execution_time" => ini_get("max_execution_time"),
                "upload_max_filesize" => ini_get("upload_max_filesize"),
                "post_max_size" => ini_get("post_max_size"),
                "max_input_vars" => ini_get("max_input_vars"),
                "max_input_time" => ini_get("max_input_time"),
                "default_socket_timeout" => ini_get("default_socket_timeout"),
                "allow_url_fopen" => ini_get("allow_url_fopen"),
                "session.save_handler" => ini_get("session.save_handler")
            ]);'"""

            ini_result = await self.wp_cli.execute_command(ini_settings_cmd)
            ini_settings = json.loads(ini_result.get("output", "{}"))

            # Get disabled functions
            disabled_cmd = "eval 'echo ini_get(\"disable_functions\");'"
            disabled_result = await self.wp_cli.execute_command(disabled_cmd)
            disabled_raw = disabled_result.get("output", "").strip()
            disabled_functions = [f.strip() for f in disabled_raw.split(",") if f.strip()]

            return {
                "success": True,
                "version": php_version,
                "sapi": php_sapi,
                "extensions": extensions,
                "ini_settings": ini_settings,
                "disabled_functions": disabled_functions,
            }

        except Exception as e:
            self.logger.error(f"PHP info failed: {str(e)}")
            return {"success": False, "error": str(e)}

    async def system_disk_usage(self) -> dict[str, Any]:
        """Get disk usage statistics"""
        if not self.wp_cli:
            return {"success": False, "error": "WP-CLI not available"}

        try:
            # Get WordPress root path
            path_cmd = "eval 'echo ABSPATH;'"
            path_result = await self.wp_cli.execute_command(path_cmd)
            wp_path = path_result.get("output", "").strip()

            # Get directory sizes using du command
            sizes = {}

            # Uploads directory
            uploads_cmd = f"eval 'echo shell_exec(\"du -sm {wp_path}wp-content/uploads 2>/dev/null | cut -f1\");'"
            try:
                uploads_result = await self.wp_cli.execute_command(uploads_cmd)
                upload_size = uploads_result.get("output", "0").strip()
                sizes["uploads_size_mb"] = (
                    float(upload_size) if upload_size and upload_size != "" else 0.0
                )
            except Exception as e:
                self.logger.warning(f"Failed to get uploads size: {e}")
                sizes["uploads_size_mb"] = 0.0

            # Plugins directory
            plugins_cmd = f"eval 'echo shell_exec(\"du -sm {wp_path}wp-content/plugins 2>/dev/null | cut -f1\");'"
            try:
                plugins_result = await self.wp_cli.execute_command(plugins_cmd)
                plugins_size = plugins_result.get("output", "0").strip()
                sizes["plugins_size_mb"] = (
                    float(plugins_size) if plugins_size and plugins_size != "" else 0.0
                )
            except Exception as e:
                self.logger.warning(f"Failed to get plugins size: {e}")
                sizes["plugins_size_mb"] = 0.0

            # Themes directory
            themes_cmd = f"eval 'echo shell_exec(\"du -sm {wp_path}wp-content/themes 2>/dev/null | cut -f1\");'"
            try:
                themes_result = await self.wp_cli.execute_command(themes_cmd)
                themes_size = themes_result.get("output", "0").strip()
                sizes["themes_size_mb"] = (
                    float(themes_size) if themes_size and themes_size != "" else 0.0
                )
            except Exception as e:
                self.logger.warning(f"Failed to get themes size: {e}")
                sizes["themes_size_mb"] = 0.0

            # Total WordPress directory
            total_cmd = f"eval 'echo shell_exec(\"du -sm {wp_path} 2>/dev/null | cut -f1\");'"
            try:
                total_result = await self.wp_cli.execute_command(total_cmd)
                total_size = total_result.get("output", "0").strip()
                sizes["wordpress_size_mb"] = (
                    float(total_size) if total_size and total_size != "" else 0.0
                )
            except Exception as e:
                self.logger.warning(f"Failed to get wordpress total size: {e}")
                sizes["wordpress_size_mb"] = 0.0

            # Database size (from our database handler logic)
            db_query = """
                SELECT ROUND(SUM(data_length + index_length) / 1024 / 1024, 2) AS size_mb
                FROM information_schema.TABLES
                WHERE table_schema = DATABASE()
            """
            db_cmd = f'db query "{db_query}" --skip-column-names'
            try:
                db_result = await self.wp_cli.execute_command(db_cmd)
                sizes["database_size_mb"] = float(db_result.get("output", "0").strip())
            except (ValueError, KeyError, Exception):
                sizes["database_size_mb"] = 0.0

            # Calculate total
            total_size = sum([sizes["wordpress_size_mb"], sizes["database_size_mb"]])

            return {
                "success": True,
                "total_size_mb": round(total_size, 2),
                **sizes,
                "breakdown": {
                    "uploads": sizes["uploads_size_mb"],
                    "plugins": sizes["plugins_size_mb"],
                    "themes": sizes["themes_size_mb"],
                    "database": sizes["database_size_mb"],
                },
            }

        except Exception as e:
            self.logger.error(f"Disk usage check failed: {str(e)}")
            return {"success": False, "error": str(e)}

    async def system_clear_all_caches(self) -> dict[str, Any]:
        """Clear all caches"""
        if not self.wp_cli:
            return {"success": False, "error": "WP-CLI not available"}

        try:
            cleared = []

            # Clear object cache
            try:
                await self.wp_cli.execute_command("cache flush")
                cleared.append("object_cache")
            except Exception as e:
                self.logger.warning(f"Object cache flush failed: {str(e)}")

            # Clear transients
            try:
                await self.wp_cli.execute_command("transient delete --all")
                cleared.append("transients")
            except Exception as e:
                self.logger.warning(f"Transient delete failed: {str(e)}")

            # Clear OPcache if available
            try:
                opcache_cmd = 'eval \'if (function_exists("opcache_reset")) { opcache_reset(); echo "cleared"; }\''
                opcache_result = await self.wp_cli.execute_command(opcache_cmd)
                if "cleared" in opcache_result.get("output", ""):
                    cleared.append("opcache")
            except Exception as e:
                self.logger.warning(f"OPcache clear failed: {str(e)}")

            return {
                "success": True,
                "message": f"Cleared {len(cleared)} cache types",
                "cleared": cleared,
            }

        except Exception as e:
            self.logger.error(f"Clear all caches failed: {str(e)}")
            return {"success": False, "error": str(e)}

    async def cron_list(self) -> dict[str, Any]:
        """List all WordPress cron jobs"""
        if not self.wp_cli:
            return {"success": False, "error": "WP-CLI not available"}

        try:
            # Get cron events
            cmd = "cron event list --format=json"
            result = await self.wp_cli.execute_command(cmd)

            events_data = json.loads(result.get("output", "[]"))

            # Parse events
            events = []
            for event in events_data:
                events.append(
                    {
                        "hook": event.get("hook", ""),
                        "timestamp": int(event.get("time", 0)),
                        "schedule": event.get("recurrence", "single"),
                        "interval": event.get("interval"),
                        "args": event.get("args", []),
                    }
                )

            # Get available schedules
            schedules_cmd = "cron schedule list --format=json"
            try:
                schedules_result = await self.wp_cli.execute_command(schedules_cmd)
                schedules_data = json.loads(schedules_result.get("output", "[]"))
                schedules = {s.get("name"): s for s in schedules_data}
            except (json.JSONDecodeError, KeyError, Exception):
                schedules = {}

            return {"success": True, "events": events, "total": len(events), "schedules": schedules}

        except Exception as e:
            self.logger.error(f"Cron list failed: {str(e)}")
            return {"success": False, "error": str(e)}

    async def cron_run(self, hook: str, args: list[Any] | None = None) -> dict[str, Any]:
        """Manually run a cron job"""
        if not self.wp_cli:
            return {"success": False, "error": "WP-CLI not available"}

        try:
            # Build command
            cmd = f"cron event run {hook}"

            # Execute cron job
            result = await self.wp_cli.execute_command(cmd)

            return {
                "success": True,
                "message": f"Cron job '{hook}' executed",
                "hook": hook,
                "output": result.get("output", ""),
            }

        except Exception as e:
            self.logger.error(f"Cron run failed: {str(e)}")
            return {"success": False, "error": str(e)}

    async def error_log(
        self, lines: int = 100, filter: str | None = None, level: str | None = None
    ) -> dict[str, Any]:
        """Get PHP error log entries"""
        if not self.wp_cli:
            return {"success": False, "error": "WP-CLI not available"}

        try:
            # Get error log path
            log_path_cmd = "eval 'echo ini_get(\"error_log\");'"
            log_path_result = await self.wp_cli.execute_command(log_path_cmd)
            log_path = log_path_result.get("output", "").strip()

            if not log_path or log_path == "":
                # Try WordPress debug log
                wp_path_cmd = "eval 'echo WP_CONTENT_DIR;'"
                wp_path_result = await self.wp_cli.execute_command(wp_path_cmd)
                wp_content = wp_path_result.get("output", "").strip()
                log_path = f"{wp_content}/debug.log"

            # Get log file size
            size_cmd = f"eval 'echo filesize(\"{log_path}\") ?? 0;'"
            try:
                size_result = await self.wp_cli.execute_command(size_cmd)
                log_size_bytes = int(size_result.get("output", "0").strip())
                log_size_mb = round(log_size_bytes / 1024 / 1024, 2)
            except (ValueError, KeyError, Exception):
                log_size_mb = 0.0

            # Read log file (last N lines)
            tail_cmd = f"eval 'exec(\"tail -n {lines} {log_path} 2>&1\");'"
            log_result = await self.wp_cli.execute_command(tail_cmd)
            log_lines = log_result.get("output", "").strip().split("\n")

            # Parse log entries
            entries = []
            for line in log_lines:
                if not line.strip():
                    continue

                # Basic parsing (PHP error log format varies)
                # Format: [timestamp] PHP Error_Type: message in file on line X
                match = re.match(r"\[([^\]]+)\]\s+PHP\s+(\w+):\s+(.+)", line)

                if match:
                    timestamp, error_type, message = match.groups()

                    # Extract file and line if present
                    file_match = re.search(r"in\s+(.+)\s+on\s+line\s+(\d+)", message)
                    file_path = file_match.group(1) if file_match else None
                    line_num = int(file_match.group(2)) if file_match else None

                    entry = {
                        "timestamp": timestamp,
                        "level": error_type.lower(),
                        "message": message,
                        "file": file_path,
                        "line": line_num,
                    }

                    # Apply filters
                    if level and entry["level"] != level.lower():
                        continue

                    if filter and filter.lower() not in message.lower():
                        continue

                    entries.append(entry)
                else:
                    # Unparsed line - include as-is
                    entries.append(
                        {
                            "timestamp": "N/A",
                            "level": "unknown",
                            "message": line,
                            "file": None,
                            "line": None,
                        }
                    )

            return {
                "success": True,
                "entries": entries,
                "total_lines": len(log_lines),
                "filtered_lines": len(entries),
                "log_size_mb": log_size_mb,
                "log_path": log_path,
            }

        except Exception as e:
            self.logger.error(f"Error log retrieval failed: {str(e)}")
            return {"success": False, "error": str(e)}
