"""OpenClaw CLI client for managing cron jobs.

Wraps `openclaw automations` commands to create, delete, and list cron jobs.
"""

import asyncio
import json
import logging
from dataclasses import dataclass
from typing import Optional

_logger = logging.getLogger("agenteval")


@dataclass
class OpenClawCron:
    """OpenClaw cron job info."""

    id: str
    name: str
    schedule: str
    enabled: bool
    state: Optional[dict] = None


class OpenClawClient:
    """Client for OpenClaw CLI commands."""

    def __init__(self, openclaw_bin: str = "openclaw"):
        self.openclaw_bin = openclaw_bin

    async def _run_command(self, *args: str) -> tuple[int, str, str]:
        """Run an OpenClaw CLI command.

        Returns:
            (returncode, stdout, stderr)
        """
        cmd = [self.openclaw_bin] + list(args)
        _logger.debug(f"Running OpenClaw command: {' '.join(cmd)}")

        process = await asyncio.create_subprocess_exec(
            *cmd,
            stdout=asyncio.subprocess.PIPE,
            stderr=asyncio.subprocess.PIPE,
        )
        stdout, stderr = await process.communicate()

        return (
            process.returncode or 0,
            stdout.decode("utf-8"),
            stderr.decode("utf-8"),
        )

    async def create_cron(
        self,
        *,
        name: str,
        schedule: str,
        skill: str,
        state: Optional[dict] = None,
    ) -> str:
        """Create a cron job.

        Args:
            name: Cron job name
            schedule: Cron schedule expression (e.g., "* * * * *")
            skill: Skill to execute
            state: Initial state (JSON)

        Returns:
            Cron job ID

        Raises:
            RuntimeError: If creation fails
        """
        args = [
            "automations",
            "create",
            schedule,
            f"--name={name}",
            f"--skill={skill}",
        ]

        if state:
            args.append(f"--state={json.dumps(state)}")

        returncode, stdout, stderr = await self._run_command(*args)

        if returncode != 0:
            raise RuntimeError(f"Failed to create cron: {stderr}")

        # Parse cron ID from output
        # Expected output format: "Created automation <id>"
        lines = stdout.strip().split("\n")
        for line in lines:
            if "Created automation" in line:
                cron_id = line.split()[-1]
                _logger.info(f"Created OpenClaw cron {cron_id}: {name}")
                return cron_id

        raise RuntimeError(f"Failed to parse cron ID from output: {stdout}")

    async def delete_cron(self, cron_id: str) -> None:
        """Delete a cron job.

        Args:
            cron_id: Cron job ID

        Raises:
            RuntimeError: If deletion fails
        """
        returncode, stdout, stderr = await self._run_command(
            "automations",
            "remove",
            cron_id,
        )

        if returncode != 0:
            raise RuntimeError(f"Failed to delete cron {cron_id}: {stderr}")

        _logger.info(f"Deleted OpenClaw cron {cron_id}")

    async def list_crons(self) -> list[OpenClawCron]:
        """List all cron jobs.

        Returns:
            List of cron jobs

        Raises:
            RuntimeError: If listing fails
        """
        returncode, stdout, stderr = await self._run_command(
            "automations",
            "list",
            "--json",
        )

        if returncode != 0:
            raise RuntimeError(f"Failed to list crons: {stderr}")

        try:
            data = json.loads(stdout)
            crons = []
            for item in data:
                crons.append(
                    OpenClawCron(
                        id=item["id"],
                        name=item.get("name", ""),
                        schedule=item.get("schedule", ""),
                        enabled=item.get("enabled", True),
                        state=item.get("state"),
                    )
                )
            return crons
        except (json.JSONDecodeError, KeyError) as e:
            raise RuntimeError(f"Failed to parse cron list: {e}") from e

    async def get_cron_state(self, cron_id: str) -> Optional[dict]:
        """Get cron job state.

        Args:
            cron_id: Cron job ID

        Returns:
            State dict, or None if not found
        """
        crons = await self.list_crons()
        for cron in crons:
            if cron.id == cron_id:
                return cron.state
        return None
