"""
Database Operations Handler

Manages WordPress database operations including:
- Export/Import
- Backup/Restore
- Optimization and Repair
- Search and Query operations

All operations require 'write' or 'admin' scope for security.
"""

import json
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 [
        # DB Export (already exists in wp_cli.py, documented here for completeness)
        {
            "name": "wp_db_export",
            "method_name": "wp_db_export",
            "description": "Export WordPress database to SQL file. Creates a timestamped backup file in /tmp directory.",
            "schema": {
                "type": "object",
                "properties": {
                    "tables": {
                        "type": "array",
                        "items": {"type": "string"},
                        "description": "Specific tables to export (default: all tables)",
                    },
                    "exclude_tables": {
                        "type": "array",
                        "items": {"type": "string"},
                        "description": "Tables to exclude from export",
                    },
                    "add_drop_table": {
                        "type": "boolean",
                        "default": True,
                        "description": "Include DROP TABLE statements",
                    },
                },
            },
            "scope": "write",
        },
        # DB Import
        {
            "name": "wp_db_import",
            "method_name": "wp_db_import",
            "description": "Import database from SQL file. DESTRUCTIVE: replaces current database. Requires admin scope.",
            "schema": {
                "type": "object",
                "properties": {
                    "file_path": {"type": "string", "description": "Path to SQL file on server"},
                    "url": {"type": "string", "description": "URL to download SQL file from"},
                    "skip_optimization": {
                        "type": "boolean",
                        "default": False,
                        "description": "Skip database optimization after import",
                    },
                },
            },
            "scope": "admin",
        },
        # DB Size Info
        {
            "name": "wp_db_size",
            "method_name": "wp_db_size",
            "description": "Get database size statistics including total size, table sizes, and row counts.",
            "schema": {"type": "object", "properties": {}},
            "scope": "read",
        },
        # DB Tables List
        {
            "name": "wp_db_tables",
            "method_name": "wp_db_tables",
            "description": "List all database tables with detailed information (size, engine, rows, collation).",
            "schema": {
                "type": "object",
                "properties": {
                    "prefix_only": {
                        "type": "boolean",
                        "default": True,
                        "description": "Show only WordPress tables (with wp_ prefix)",
                    }
                },
            },
            "scope": "read",
        },
        # DB Search
        {
            "name": "wp_db_search",
            "method_name": "wp_db_search",
            "description": "Search database for specific strings. Useful for finding content, debugging, or data migration.",
            "schema": {
                "type": "object",
                "properties": {
                    "search_string": {"type": "string", "description": "String to search for"},
                    "tables": {
                        "type": "array",
                        "items": {"type": "string"},
                        "description": "Specific tables to search",
                    },
                    "regex": {
                        "type": "boolean",
                        "default": False,
                        "description": "Use regex pattern matching",
                    },
                    "case_sensitive": {
                        "type": "boolean",
                        "default": False,
                        "description": "Case-sensitive search",
                    },
                    "max_results": {
                        "type": "integer",
                        "default": 100,
                        "minimum": 1,
                        "maximum": 1000,
                        "description": "Maximum results to return",
                    },
                },
                "required": ["search_string"],
            },
            "scope": "read",
        },
        # DB Query (read-only SELECT)
        {
            "name": "wp_db_query",
            "method_name": "wp_db_query",
            "description": "Execute read-only SQL query (SELECT, SHOW, DESCRIBE only). For advanced users and debugging.",
            "schema": {
                "type": "object",
                "properties": {
                    "query": {
                        "type": "string",
                        "description": "SQL query to execute (SELECT only)",
                    },
                    "max_rows": {
                        "type": "integer",
                        "default": 1000,
                        "minimum": 1,
                        "maximum": 10000,
                        "description": "Maximum rows to return",
                    },
                },
                "required": ["query"],
            },
            "scope": "write",
        },
        # DB Repair
        {
            "name": "wp_db_repair",
            "method_name": "wp_db_repair",
            "description": "Repair corrupted database tables. Runs REPAIR TABLE on all WordPress tables.",
            "schema": {
                "type": "object",
                "properties": {
                    "tables": {
                        "type": "array",
                        "items": {"type": "string"},
                        "description": "Specific tables to repair (default: all tables)",
                    }
                },
            },
            "scope": "write",
        },
    ]


class DatabaseHandler:
    """Handles WordPress database operations"""

    def __init__(self, client: WordPressClient, wp_cli: WPCLIManager | None = None):
        """
        Initialize Database 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_db_export(
        self,
        tables: list[str] | None = None,
        exclude_tables: list[str] | None = None,
        add_drop_table: bool = True,
    ) -> dict[str, Any]:
        """
        Export WordPress database to SQL file

        Uses WP-CLI: wp db export
        """
        if not self.wp_cli:
            return {
                "success": False,
                "error": "WP-CLI not available. Container name not configured.",
            }

        try:
            # Build WP-CLI command
            cmd = "db export /tmp/backup-$(date +%Y%m%d-%H%M%S).sql"

            if tables:
                cmd += f" --tables={','.join(tables)}"

            if exclude_tables:
                cmd += f" --exclude_tables={','.join(exclude_tables)}"

            if not add_drop_table:
                cmd += " --no-add-drop-table"

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

            return {
                "success": True,
                "message": "Database exported successfully",
                "file": result.get("output", ""),
                "command": cmd,
            }

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

    async def wp_db_import(
        self, file_path: str | None = None, url: str | None = None, skip_optimization: bool = False
    ) -> dict[str, Any]:
        """
        Import database from SQL file

        ⚠️ DESTRUCTIVE OPERATION - Requires admin scope
        """
        if not self.wp_cli:
            return {"success": False, "error": "WP-CLI not available"}

        if not file_path and not url:
            return {"success": False, "error": "Either file_path or url is required"}

        try:
            # Download file if URL provided
            if url:
                # Use wget or curl to download
                download_cmd = f"wget -O /tmp/import.sql '{url}'"
                await self.wp_cli.execute_command(f"eval '{download_cmd}'")
                file_path = "/tmp/import.sql"

            # Import database
            cmd = f"db import {file_path}"
            await self.wp_cli.execute_command(cmd)

            # Optimize unless skipped
            if not skip_optimization:
                await self.wp_cli.execute_command("db optimize")

            return {
                "success": True,
                "message": "Database imported successfully",
                "file": file_path,
                "optimized": not skip_optimization,
            }

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

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

        try:
            # Get total database size first
            total_query = """
                SELECT ROUND(SUM(data_length + index_length) / 1024 / 1024, 2) AS total_mb,
                       SUM(table_rows) AS total_rows,
                       COUNT(*) AS table_count
                FROM information_schema.TABLES
                WHERE table_schema = DATABASE()
            """

            total_cmd = f'db query "{total_query}" --skip-column-names'
            total_result = await self.wp_cli.execute_command(total_cmd)

            # Parse tab-separated output
            total_output = total_result.get("output", "0\t0\t0").strip()
            total_parts = total_output.split("\t")

            total_size_mb = (
                float(total_parts[0]) if len(total_parts) > 0 and total_parts[0] else 0.0
            )
            total_rows = int(total_parts[1]) if len(total_parts) > 1 and total_parts[1] else 0
            table_count = int(total_parts[2]) if len(total_parts) > 2 and total_parts[2] else 0

            # Get individual table sizes (top 50 largest tables)
            tables_query = """
                SELECT table_name,
                       ROUND((data_length + index_length) / 1024 / 1024, 2) AS size_mb,
                       table_rows
                FROM information_schema.TABLES
                WHERE table_schema = DATABASE()
                ORDER BY (data_length + index_length) DESC
                LIMIT 50
            """

            tables_cmd = f'db query "{tables_query}" --skip-column-names'
            tables_result = await self.wp_cli.execute_command(tables_cmd)

            # Parse table results (tab-separated)
            tables_output = tables_result.get("output", "").strip()
            tables = []

            if tables_output:
                for line in tables_output.split("\n"):
                    parts = line.split("\t")
                    if len(parts) >= 3:
                        tables.append(
                            {
                                "table_name": parts[0],
                                "size_mb": float(parts[1]) if parts[1] else 0.0,
                                "table_rows": int(parts[2]) if parts[2] else 0,
                            }
                        )

            return {
                "success": True,
                "total_size_mb": total_size_mb,
                "total_rows": total_rows,
                "table_count": table_count,
                "tables": tables,
                "note": "Showing top 50 largest tables",
            }

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

    async def wp_db_tables(self, prefix_only: bool = True) -> dict[str, Any]:
        """List all database tables with details"""
        if not self.wp_cli:
            return {"success": False, "error": "WP-CLI not available"}

        try:
            # Query for table information
            query = """
                SELECT
                    table_name,
                    engine,
                    table_rows,
                    ROUND((data_length / 1024 / 1024), 2),
                    ROUND((index_length / 1024 / 1024), 2),
                    ROUND(((data_length + index_length) / 1024 / 1024), 2),
                    table_collation
                FROM information_schema.TABLES
                WHERE table_schema = DATABASE()
            """

            if prefix_only:
                # Get WordPress table prefix
                prefix_result = await self.wp_cli.execute_command("config get table_prefix")
                prefix = prefix_result.get("output", "wp_").strip()
                query += f" AND table_name LIKE '{prefix}%'"

            query += " ORDER BY (data_length + index_length) DESC"

            # Use --skip-column-names for MariaDB compatibility (no --format=json)
            cmd = f'db query "{query}" --skip-column-names'
            result = await self.wp_cli.execute_command(cmd)

            # Parse tab-separated output
            tables_output = result.get("output", "").strip()
            tables = []

            if tables_output:
                for line in tables_output.split("\n"):
                    parts = line.split("\t")
                    if len(parts) >= 7:
                        tables.append(
                            {
                                "name": parts[0],
                                "engine": parts[1],
                                "rows": int(parts[2]) if parts[2] and parts[2] != "NULL" else 0,
                                "data_size_mb": (
                                    float(parts[3]) if parts[3] and parts[3] != "NULL" else 0.0
                                ),
                                "index_size_mb": (
                                    float(parts[4]) if parts[4] and parts[4] != "NULL" else 0.0
                                ),
                                "total_size_mb": (
                                    float(parts[5]) if parts[5] and parts[5] != "NULL" else 0.0
                                ),
                                "collation": parts[6] if parts[6] != "NULL" else None,
                            }
                        )

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

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

    async def wp_db_search(
        self,
        search_string: str,
        tables: list[str] | None = None,
        regex: bool = False,
        case_sensitive: bool = False,
        max_results: int = 100,
    ) -> dict[str, Any]:
        """Search database for specific strings"""
        if not self.wp_cli:
            return {"success": False, "error": "WP-CLI not available"}

        try:
            # Build search-replace command in dry-run mode
            cmd = f'search-replace "{search_string}" "{search_string}" --dry-run --format=count'

            if tables:
                cmd += f" {' '.join(tables)}"

            if regex:
                cmd += " --regex"

            if not case_sensitive:
                cmd += " --skip-columns=guid"  # Common practice

            result = await self.wp_cli.execute_command(cmd)

            return {
                "success": True,
                "search_string": search_string,
                "matches_found": result.get("output", "0"),
                "dry_run": True,
            }

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

    async def wp_db_query(self, query: str, max_rows: int = 1000) -> dict[str, Any]:
        """
        Execute read-only SQL query

        Security: Only SELECT, SHOW, DESCRIBE queries allowed
        """
        if not self.wp_cli:
            return {"success": False, "error": "WP-CLI not available"}

        # Validate query (additional server-side validation)
        query_upper = query.strip().upper()
        allowed_starts = ("SELECT", "SHOW", "DESCRIBE", "DESC", "EXPLAIN")

        if not any(query_upper.startswith(cmd) for cmd in allowed_starts):
            return {
                "success": False,
                "error": "Only SELECT, SHOW, DESCRIBE, and EXPLAIN queries allowed",
            }

        forbidden = [
            "INSERT",
            "UPDATE",
            "DELETE",
            "DROP",
            "ALTER",
            "CREATE",
            "TRUNCATE",
            "REPLACE",
            "GRANT",
            "REVOKE",
        ]

        for keyword in forbidden:
            if keyword in query_upper:
                return {"success": False, "error": f"Forbidden keyword in query: {keyword}"}

        try:
            # Add LIMIT if not present
            if "LIMIT" not in query_upper:
                query = f"{query.rstrip(';')} LIMIT {max_rows}"

            # Execute query with --skip-column-names for MariaDB compatibility
            # First, get column names separately if it's a SELECT
            results = []

            if query_upper.startswith("SELECT"):
                # For SELECT queries, we need to parse the tab-separated output
                cmd = f'db query "{query}" --skip-column-names'
                result = await self.wp_cli.execute_command(cmd)

                # Get output
                output = result.get("output", "").strip()

                if output:
                    # Parse tab-separated values
                    lines = output.split("\n")

                    # For simple queries, try to detect column structure
                    # We'll return as a list of dictionaries with column indices
                    for idx, line in enumerate(lines):
                        values = line.split("\t")
                        # Create a row dict with column indices
                        row = {f"col_{i}": val for i, val in enumerate(values)}
                        results.append(row)

                        # Limit results
                        if idx >= max_rows - 1:
                            break
            else:
                # For SHOW, DESCRIBE, etc., just return raw output
                cmd = f'db query "{query}"'
                result = await self.wp_cli.execute_command(cmd)
                output = result.get("output", "").strip()

                # Return as formatted message
                return {
                    "success": True,
                    "output": output,
                    "query": query,
                    "note": "Results displayed as plain text",
                }

            return {
                "success": True,
                "results": results,
                "row_count": len(results),
                "query": query,
                "note": "Columns are numbered as col_0, col_1, etc. due to MariaDB compatibility mode.",
            }

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

    async def wp_db_repair(self, tables: list[str] | None = None) -> dict[str, Any]:
        """Repair corrupted database tables"""
        if not self.wp_cli:
            return {"success": False, "error": "WP-CLI not available"}

        try:
            # Get list of tables to repair
            if not tables:
                # Get all WordPress tables
                table_list = await self.wp_db_tables(prefix_only=True)
                if not table_list.get("success"):
                    return table_list

                tables = [t["name"] for t in table_list.get("tables", [])]

            # Repair each table
            results = []
            for table in tables:
                try:
                    query = f"REPAIR TABLE {table}"
                    cmd = f'db query "{query}" --format=json'
                    result = await self.wp_cli.execute_command(cmd)

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

                    results.append(
                        {
                            "table": table,
                            "status": "Repaired" if repair_result else "OK",
                            "message": str(repair_result),
                        }
                    )

                except Exception as e:
                    results.append({"table": table, "status": "Failed", "message": str(e)})

            # Count successes/failures
            success_count = sum(1 for r in results if r["status"] != "Failed")
            failed_count = len(results) - success_count

            return {
                "success": True,
                "total_tables": len(results),
                "success_count": success_count,
                "failed_count": failed_count,
                "results": results,
            }

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