"""
Feature 41: Web Search Tool
Feature 42: File System Tool
Feature 43: SQL Database Tool
Feature 45: REST API Caller Tool
Feature 46: Python Code Execution Tool
Feature 60: Custom Tool Plugin System
"""
import os
import json
import subprocess
import tempfile
from .base import BaseTool


# ─── Feature 41: Web Search ───────────────────────────────────────────────────
class WebSearch(BaseTool):
    """Search the web using DuckDuckGo (no API key needed)."""
    name = "web_search"
    description = "Search the web for current information. Input: search query string."

    def run(self, query: str) -> str:
        try:
            import urllib.request
            import urllib.parse
            import re
            url = f"https://html.duckduckgo.com/html/?q={urllib.parse.quote(query)}"
            req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"})
            with urllib.request.urlopen(req, timeout=10) as resp:
                html = resp.read().decode("utf-8")
            snippets = re.findall(r'class="result__snippet"[^>]*>(.*?)</a>', html, re.DOTALL)
            cleaned = [re.sub(r"<[^>]+>", "", s).strip() for s in snippets[:5]]
            return "\n".join(cleaned) if cleaned else "No results found."
        except Exception as e:
            return f"Web search error: {e}"


# ─── Feature 42: File System ──────────────────────────────────────────────────
class FileSystem(BaseTool):
    """Read and write files. Input: 'read:<path>' or 'write:<path>|<content>'"""
    name = "filesystem"
    description = "Read or write files. Use 'read:<path>' or 'write:<path>|<content>'"

    def run(self, input: str) -> str:
        try:
            if input.startswith("read:"):
                path = input[5:].strip()
                if not os.path.exists(path):
                    return f"File not found: {path}"
                with open(path, "r", encoding="utf-8") as f:
                    return f.read()
            elif input.startswith("write:"):
                parts = input[6:].split("|", 1)
                if len(parts) != 2:
                    return "Format: write:<path>|<content>"
                path, content = parts[0].strip(), parts[1].strip()
                os.makedirs(os.path.dirname(path) or ".", exist_ok=True)
                with open(path, "w", encoding="utf-8") as f:
                    f.write(content)
                return f"Written to {path}"
            elif input.startswith("list:"):
                path = input[5:].strip() or "."
                files = os.listdir(path)
                return "\n".join(files)
            else:
                return "Unknown command. Use read:<path>, write:<path>|<content>, or list:<dir>"
        except Exception as e:
            return f"Filesystem error: {e}"


# ─── Feature 43: SQL Database ─────────────────────────────────────────────────
class SQLDatabase(BaseTool):
    """Run SQL queries on a SQLite database. Input: SQL query string."""
    name = "database"
    description = "Run SQL queries. Input: SQL query. Default: in-memory SQLite database."

    def __init__(self, db_path: str = ":memory:"):
        self.db_path = db_path

    def run(self, query: str) -> str:
        try:
            import sqlite3
            conn = sqlite3.connect(self.db_path)
            cursor = conn.cursor()
            cursor.execute(query)
            if query.strip().upper().startswith("SELECT"):
                rows = cursor.fetchall()
                cols = [d[0] for d in cursor.description] if cursor.description else []
                conn.close()
                if not rows:
                    return "No results."
                result = [", ".join(str(v) for v in row) for row in rows]
                return f"Columns: {cols}\n" + "\n".join(result)
            else:
                conn.commit()
                conn.close()
                return f"Query executed. Rows affected: {cursor.rowcount}"
        except Exception as e:
            return f"Database error: {e}"


# ─── Feature 45: REST API Caller ──────────────────────────────────────────────
class RestAPI(BaseTool):
    """Call any REST API. Input: 'GET:<url>' or 'POST:<url>|<json_body>'"""
    name = "rest_api"
    description = "Call REST APIs. Use 'GET:<url>' or 'POST:<url>|<json_body>'"

    def run(self, input: str) -> str:
        try:
            import urllib.request
            if input.startswith("GET:"):
                url = input[4:].strip()
                req = urllib.request.Request(url, headers={"User-Agent": "Synapse/2.0"})
                with urllib.request.urlopen(req, timeout=10) as resp:
                    return resp.read().decode("utf-8")[:2000]
            elif input.startswith("POST:"):
                parts = input[5:].split("|", 1)
                url = parts[0].strip()
                body = parts[1].strip().encode("utf-8") if len(parts) > 1 else b""
                req = urllib.request.Request(url, data=body, method="POST",
                    headers={"Content-Type": "application/json", "User-Agent": "Synapse/2.0"})
                with urllib.request.urlopen(req, timeout=10) as resp:
                    return resp.read().decode("utf-8")[:2000]
            else:
                return "Format: GET:<url> or POST:<url>|<json_body>"
        except Exception as e:
            return f"API error: {e}"


# ─── Feature 46: Code Execution ───────────────────────────────────────────────
class CodeExecutor(BaseTool):
    """Execute Python code safely. Input: Python code string."""
    name = "code_exec"
    description = "Execute Python code and return output. Input: Python code string."

    def __init__(self, timeout: int = 10, safe_mode: bool = True):
        self.timeout = timeout
        self.safe_mode = safe_mode

    def run(self, code: str) -> str:
        try:
            # Write to temp file and execute
            with tempfile.NamedTemporaryFile(mode="w", suffix=".py", delete=False) as f:
                f.write(code)
                tmp_path = f.name

            result = subprocess.run(
                ["python", tmp_path],
                capture_output=True, text=True,
                timeout=self.timeout
            )
            os.unlink(tmp_path)

            output = result.stdout.strip()
            errors = result.stderr.strip()

            if errors:
                return f"Output:\n{output}\n\nErrors:\n{errors}" if output else f"Error:\n{errors}"
            return output or "Code executed (no output)."
        except subprocess.TimeoutExpired:
            return f"Code execution timed out after {self.timeout}s"
        except Exception as e:
            return f"Execution error: {e}"


# ─── Feature 60: Custom Tool Base ─────────────────────────────────────────────
class CustomTool(BaseTool):
    """
    Feature 60: Custom tool plugin system.
    Developers can create their own tools by subclassing this.

    Example:
        class MyTool(CustomTool):
            name = "my_tool"
            description = "Does something custom"

            def run(self, input: str) -> str:
                return f"Custom result for: {input}"
    """
    name = "custom"
    description = "Custom tool base class"

    def run(self, input: str) -> str:
        raise NotImplementedError("Override run() in your custom tool.")
