import logging
from typing import Optional
from .models import AgentModel, AgentVersion, AgentRun
from .client import EzopClient

logger = logging.getLogger(__name__)


class Agent:

    def __init__(self, model: AgentModel, version: AgentVersion):
        self.model = model
        self.version = version
        self.client = EzopClient()
        self.current_run: Optional[AgentRun] = None

    @classmethod
    def init(
        cls,
        name: str,
        owner: str,
        version: str,
        runtime: str,
        *,
        description: Optional[str] = None,
        default_permissions: Optional[list[str]] = None,
        permissions: Optional[list[str]] = None,
        changelog: Optional[str] = None,
    ) -> "Agent":
        """
        Initialize an Ezop agent and register it with the Ezop platform.
        Creates the agent record and a corresponding version record.
        """
        logger.info(
            "Initializing agent name=%s owner=%s version=%s runtime=%s",
            name,
            owner,
            version,
            runtime,
        )
        client = EzopClient()

        agent_data = client.register_agent(
            {
                "name": name,
                "owner": owner,
                "runtime": runtime,
                "description": description,
                "default_permissions": default_permissions,
            }
        )["data"]

        model = AgentModel(
            id=agent_data["id"],
            name=agent_data["name"],
            owner=agent_data["owner"],
            runtime=agent_data.get("runtime"),
            description=agent_data.get("description"),
            default_permissions=agent_data.get("default_permissions") or [],
        )
        logger.debug("Agent model built id=%s", model.id)

        version_data = client.create_version(
            model.id,
            {
                "version": version,
                "permissions": permissions,
                "changelog": changelog,
            },
        )["data"]

        agent_version = AgentVersion(
            id=version_data["id"],
            agent_id=model.id,
            version=version_data["version"],
            permissions=version_data.get("permissions") or [],
            changelog=version_data.get("changelog"),
        )
        logger.debug("Agent version built id=%s", agent_version.id)

        logger.info("Agent initialized id=%s version_id=%s", model.id, agent_version.id)
        return cls(model, agent_version)

    def start_run(self) -> AgentRun:
        """Start a new run for this agent version."""
        logger.info(
            "Starting run for agent id=%s version_id=%s", self.model.id, self.version.id
        )
        run_data = self.client.start_run(self.model.id, self.version.id)["data"]
        self.current_run = AgentRun(
            id=run_data["id"],
            agent_id=self.model.id,
            version_id=self.version.id,
            status=run_data.get("status", "running"),
        )
        logger.debug(
            "Run created id=%s status=%s", self.current_run.id, self.current_run.status
        )
        return self.current_run

    def end_run(
        self,
        status: str = "running",
        total_tokens: Optional[int] = None,
        total_cost: Optional[float] = None,
        metadata: Optional[dict] = None,
        message: Optional[str] = None,
    ) -> AgentRun:
        """End the current run.

        Args:
            status: Final status of the run (e.g. "completed", "failed").
            message: Optional human-readable message, e.g. a failure reason.
        """
        if self.current_run is None:
            logger.error("end_run called with no active run")
            raise RuntimeError("No active run. Call start_run() first.")

        logger.info("Ending run id=%s status=%s", self.current_run.id, status)
        run_data = self.client.end_run(
            self.current_run.id,
            status=status,
            total_tokens=total_tokens,
            total_cost=total_cost,
            metadata=metadata,
            message=message,
        )["data"]
        self.current_run.status = run_data.get("status", status)
        self.current_run.total_tokens = run_data.get("total_tokens")
        self.current_run.total_cost = run_data.get("total_cost")
        self.current_run.metadata = run_data.get("metadata")
        self.current_run.message = run_data.get("message")
        logger.debug(
            "Run ended id=%s status=%s total_tokens=%s total_cost=%s",
            self.current_run.id,
            self.current_run.status,
            self.current_run.total_tokens,
            self.current_run.total_cost,
        )
        return self.current_run
