import subprocess
import os
import json
from typing import Optional
import structlog

from .base_executor import BaseExecutor, ExecutorResult
from app.configs import settings

logger = structlog.get_logger()


class OpenHandsExecutor(BaseExecutor):
    """
    OpenHands Runtime 执行器
    通过 Docker 启动 OpenHands 容器执行任务
    """

    name = "openhands"
    DOCKER_IMAGE = "ghcr.io/all-hands-ai/openhands:main"

    def run(self, task: str, context: Optional[dict] = None) -> ExecutorResult:
        self.logger.info("OpenHands executor running task", task=task[:100])

        if not self._has_docker():
            return ExecutorResult(
                success=False,
                output="",
                error="Docker not available. OpenHands requires Docker.",
            )

        return self._run_via_docker(task, context)

    def _has_docker(self) -> bool:
        try:
            result = subprocess.run(
                ["docker", "info"],
                capture_output=True,
                text=True,
                timeout=10,
            )
            return result.returncode == 0
        except (FileNotFoundError, subprocess.TimeoutExpired):
            return False

    def _run_via_docker(self, task: str, context: Optional[dict] = None) -> ExecutorResult:
        context_prompt = self._build_context_prompt(context)
        full_task = f"{context_prompt}\n\n{task}" if context_prompt else task

        sandbox_vol = os.path.abspath(self.repo_path)
        env_vars = [
            "-e", f"ANTHROPIC_API_KEY={settings.anthropic_api_key}",
            "-e", f"OPENAI_API_KEY={settings.openai_api_key}",
            "-e", "SANDBOX_USER_ID=1000",
        ]

        cmd = [
            "docker", "run", "--rm",
            "-v", f"{sandbox_vol}:/workspace",
            "-v", "/var/run/docker.sock:/var/run/docker.sock",
            *env_vars,
            self.DOCKER_IMAGE,
            "python", "-m", "openhands.core.main",
            "-t", full_task,
        ]

        try:
            result = subprocess.run(
                cmd,
                capture_output=True,
                text=True,
                timeout=600,
            )
            return ExecutorResult(
                success=result.returncode == 0,
                output=result.stdout,
                error=result.stderr,
                exit_code=result.returncode,
            )
        except subprocess.TimeoutExpired:
            return ExecutorResult(success=False, output="", error="OpenHands timeout (600s)")
        except Exception as e:
            return ExecutorResult(success=False, output="", error=str(e))

    def health_check(self) -> bool:
        return self._has_docker()
