"""Tool for reading and writing system clipboard."""

from __future__ import annotations

import asyncio
import json
import subprocess
import sys
from typing import Any

from .base import Tool

_MAX_CLIPBOARD_CHARS = 100_000


class ClipboardTool(Tool):
    """Read from and write to the system clipboard."""

    @property
    def name(self) -> str:
        return "clipboard"

    @property
    def description(self) -> str:
        return "Read from or write to the system clipboard."

    @property
    def parameters(self) -> dict[str, Any]:
        return {
            "type": "object",
            "properties": {
                "action": {
                    "type": "string",
                    "enum": ["read", "write"],
                    "description": "read: get clipboard contents. write: set clipboard contents.",
                },
                "text": {
                    "type": "string",
                    "description": "Text to write to clipboard (required for write).",
                },
            },
            "required": ["action"],
        }

    async def execute(self, **kwargs: Any) -> str:
        action = kwargs["action"]

        if action == "read":
            return await self._read()
        if action == "write":
            text = kwargs.get("text", "")
            if not text:
                return json.dumps({"error": "text is required for write action"})
            return await self._write(text)
        return json.dumps({"error": f"Unknown action: {action}"})

    async def _read(self) -> str:
        try:
            if sys.platform == "darwin":
                cmd = ["pbpaste"]
            elif sys.platform == "win32":
                cmd = ["powershell", "-command", "Get-Clipboard"]
            else:
                cmd = ["xclip", "-selection", "clipboard", "-o"]

            proc = await asyncio.create_subprocess_exec(
                *cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE,
            )
            stdout, stderr = await proc.communicate()

            if proc.returncode != 0:
                return json.dumps({"error": f"Clipboard read failed: {stderr.decode()[:200]}"})

            content = stdout.decode("utf-8", errors="replace")
            if len(content) > _MAX_CLIPBOARD_CHARS:
                content = content[:_MAX_CLIPBOARD_CHARS] + "\n... [truncated]"

            return json.dumps({"ok": True, "action": "read", "length": len(content), "content": content})
        except FileNotFoundError:
            return json.dumps({"error": "Clipboard utility not found (pbpaste/xclip/powershell)"})
        except Exception as exc:
            return json.dumps({"error": str(exc)})

    async def _write(self, text: str) -> str:
        try:
            if sys.platform == "darwin":
                cmd = ["pbcopy"]
            elif sys.platform == "win32":
                cmd = ["powershell", "-command", "Set-Clipboard", "-Value", text]
                proc = await asyncio.create_subprocess_exec(
                    *cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE,
                )
                _, stderr = await proc.communicate()
                if proc.returncode != 0:
                    return json.dumps({"error": f"Clipboard write failed: {stderr.decode()[:200]}"})
                return json.dumps({"ok": True, "action": "write", "length": len(text)})
            else:
                cmd = ["xclip", "-selection", "clipboard"]

            proc = await asyncio.create_subprocess_exec(
                *cmd, stdin=asyncio.subprocess.PIPE, stdout=asyncio.subprocess.PIPE,
                stderr=asyncio.subprocess.PIPE,
            )
            _, stderr = await proc.communicate(input=text.encode("utf-8"))
            if proc.returncode != 0:
                return json.dumps({"error": f"Clipboard write failed: {stderr.decode()[:200]}"})

            return json.dumps({"ok": True, "action": "write", "length": len(text)})
        except FileNotFoundError:
            return json.dumps({"error": "Clipboard utility not found (pbcopy/xclip/powershell)"})
        except Exception as exc:
            return json.dumps({"error": str(exc)})
