import subprocess
import os
from typing import Optional
import structlog

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

logger = structlog.get_logger()


class CodexExecutor(BaseExecutor):
    """
    OpenAI Codex CLI 执行器
    使用 codex CLI 工具执行任务
    """

    name = "codex"

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

        if not self._has_codex_cli():
            return self._run_via_openai_api(task, context)

        return self._run_via_cli(task, context)

    def _has_codex_cli(self) -> bool:
        try:
            result = subprocess.run(
                ["codex", "--version"],
                capture_output=True,
                text=True,
                timeout=5,
            )
            return result.returncode == 0
        except (FileNotFoundError, subprocess.TimeoutExpired):
            return False

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

        try:
            result = subprocess.run(
                ["codex", "--approval-mode", "full-auto", full_prompt],
                capture_output=True,
                text=True,
                timeout=300,
                cwd=self.repo_path,
                env={**os.environ, "OPENAI_API_KEY": settings.openai_api_key},
            )
            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="Codex CLI timeout (300s)")
        except Exception as e:
            return ExecutorResult(success=False, output="", error=str(e))

    def _run_via_openai_api(self, task: str, context: Optional[dict] = None) -> ExecutorResult:
        try:
            from openai import OpenAI
            client = OpenAI(api_key=settings.openai_api_key)
            context_prompt = self._build_context_prompt(context)
            prompt = f"{context_prompt}\n\n{task}" if context_prompt else task

            response = client.chat.completions.create(
                model="gpt-4o",
                messages=[
                    {"role": "system", "content": "You are an expert software engineer. Implement the requested task with clean, production-quality code."},
                    {"role": "user", "content": prompt},
                ],
                max_tokens=8096,
            )
            return ExecutorResult(success=True, output=response.choices[0].message.content)
        except Exception as e:
            return ExecutorResult(success=False, output="", error=str(e))

    def health_check(self) -> bool:
        return self._has_codex_cli() or bool(settings.openai_api_key)
