from __future__ import annotations

import json
from typing import Any

from ..models import ProviderResponse, ToolProposal
from ..scenarios import Scenario
from .base import (
    SYSTEM_INSTRUCTION,
    TOOL_PARAMETERS,
    ProviderAdapter,
    ProviderError,
    post_json,
    scenario_prompt,
)


class OpenAIAdapter(ProviderAdapter):
    provider = "openai"

    def propose(self, scenario: Scenario) -> ProviderResponse:
        payload = {
            "model": self.model,
            "instructions": SYSTEM_INSTRUCTION,
            "input": scenario_prompt(scenario),
            "store": False,
            "max_output_tokens": 500,
            "tools": [
                {
                    "type": "function",
                    "name": "propose_action",
                    "description": "Propose one synthetic action for policy evaluation.",
                    "parameters": TOOL_PARAMETERS,
                    # Nested synthetic arguments are intentionally open-ended and
                    # are validated by the local policy/oracle layer after return.
                    "strict": False,
                }
            ],
            "tool_choice": {"type": "function", "name": "propose_action"},
            "parallel_tool_calls": False,
        }
        raw = post_json(
            "https://api.openai.com/v1/responses",
            {
                "Authorization": f"Bearer {self._api_key}",
                "Content-Type": "application/json",
            },
            payload,
            self.timeout_seconds,
        )
        proposals: list[ToolProposal] = []
        text_parts: list[str] = []
        for item in raw.get("output", []):
            if item.get("type") == "function_call":
                try:
                    arguments = json.loads(item.get("arguments", "{}"))
                except json.JSONDecodeError as exc:
                    raise ProviderError("OpenAI returned invalid tool arguments") from exc
                proposals.append(
                    ToolProposal(
                        name=str(item.get("name", "")),
                        arguments=arguments,
                        call_id=str(item.get("call_id", item.get("id", ""))),
                    )
                )
            elif item.get("type") == "message":
                for content in item.get("content", []):
                    if content.get("type") in {"output_text", "text"}:
                        text_parts.append(str(content.get("text", "")))
        usage = raw.get("usage", {})
        return ProviderResponse(
            provider=self.provider,
            model=self.model,
            text="\n".join(text_parts),
            proposals=tuple(proposals),
            input_tokens=int(usage.get("input_tokens", 0)),
            output_tokens=int(usage.get("output_tokens", 0)),
            raw_stop_reason=str(raw.get("status", "")),
        )
