from __future__ import annotations

import logging
from typing import Any

from .common import DesktopAutomationError

logger = logging.getLogger("dscons.desktop_automation.mcp")


class DesktopMcpClientMixin:
    """MCP UI automation client calls for window focusing and coordinate targeting."""

    async def _run_mcp_server_tool(
        self, tool_name: str, arguments: dict[str, Any]
    ) -> dict[str, Any]:
        """Execute a local helper script that calls MCP server tools directly."""
        script_path = Path(self.mcp_workspace) / "scripts" / "invoke_tool.py"
        if not script_path.exists():
            raise DesktopAutomationError(f"MCP invoke script not found: {script_path}")

        process = await asyncio.create_subprocess_exec(
            self.python_bin,
            str(script_path),
            tool_name,
            json.dumps(arguments, ensure_ascii=False),
            stdout=asyncio.subprocess.PIPE,
            stderr=asyncio.subprocess.PIPE,
            cwd=self.mcp_workspace,
            env={
                "PYTHONPATH": str(Path(self.mcp_workspace) / "src"),
                "DSCONS_PROJECT_ROOT": self.project_root,
                "ZALO_APP_NAME": "Zalo",
                "SCREENSHOT_DIR": str(
                    Path(self.mcp_workspace) / "artifacts" / "screenshots"
                ),
                "DESKTOP_AUTOMATION_LOG_DIR": str(
                    Path(self.mcp_workspace) / "artifacts" / "logs"
                ),
            },
        )
        stdout, stderr = await process.communicate()

        if process.returncode != 0:
            raise DesktopAutomationError(
                f"MCP tool {tool_name} failed with exit code {process.returncode}: {stderr.decode('utf-8', errors='replace').strip()}"
            )

        try:
            result = json.loads(stdout.decode("utf-8"))
        except json.JSONDecodeError as exc:
            raise DesktopAutomationError(
                f"Invalid MCP JSON output for {tool_name}"
            ) from exc

        if not isinstance(result, dict):
            raise DesktopAutomationError(
                f"MCP tool {tool_name} returned non-object payload"
            )

        return result

    async def focus_app(
        self, app_name: str, bundle_id: str | None = None
    ) -> dict[str, Any]:
        """Focus an application window."""
        try:
            result = await self._run_mcp_server_tool(
                "app_activate", {"app_name": app_name}
            )
            result.setdefault("data", {})
            result["data"]["bundle_id"] = bundle_id
            result["data"]["backend"] = "local_mcp_direct"
            return result
        except Exception as exc:
            return {
                "ok": False,
                "action": "focus_app",
                "timestamp": _utc_timestamp(),
                "data": {
                    "app_name": app_name,
                    "bundle_id": bundle_id,
                    "backend": "local_placeholder",
                    "implemented": False,
                },
                "artifacts": {},
                "error": {
                    "code": "focus_app_failed",
                    "message": str(exc),
                    "details": {},
                },
            }

    async def find_text_target(
        self,
        text: str,
        region: dict[str, int] | None = None,
        match_mode: str = "contains",
    ) -> dict[str, Any]:
        """Find visible UI text on screen and return candidate bounds."""
        return {
            "ok": False,
            "action": "find_text_target",
            "timestamp": _utc_timestamp(),
            "data": {
                "text": text,
                "region": region,
                "match_mode": match_mode,
                "backend": "unsupported",
            },
            "artifacts": {},
            "error": {
                "code": "unsupported_operation",
                "message": "Screen OCR/text search is not part of the current DSCons desktop backend.",
                "details": {},
            },
        }

    async def capture_screenshot(
        self,
        region: dict[str, int] | None = None,
    ) -> dict[str, Any]:
        """Capture a screenshot for verification or OCR."""
        try:
            result = await self._run_mcp_server_tool("desktop_screenshot", {})
            result.setdefault("data", {})
            result["data"]["region"] = region
            result["data"]["backend"] = "local_mcp_direct"
            return result
        except Exception as exc:
            return {
                "ok": False,
                "action": "capture_screenshot",
                "timestamp": _utc_timestamp(),
                "data": {
                    "region": region,
                    "backend": "mcp_error",
                },
                "artifacts": {},
                "error": {
                    "code": "capture_screenshot_failed",
                    "message": str(exc),
                    "details": {},
                },
            }
