"""
Platform integration for sending execution status updates.
"""
import logging
from datetime import datetime, timezone
from enum import StrEnum
import httpx

from .models import ExecutionRun, TaskRun, StepRun
from .observers import Observer

logger = logging.getLogger('zsynctech_studio_sdk.platform')


def get_utc_now() -> str:
    """Get the current UTC datetime as an ISO string.

    Returns:
        str: Current UTC datetime in ISO format with 'Z' suffix.
    """
    return datetime.now(timezone.utc).isoformat(timespec='milliseconds').replace('+00:00', 'Z')


class ExecutionStatus(StrEnum):
    """Platform execution status."""
    WAITING = 'WAITING'
    RUNNING = 'RUNNING'
    FINISHED = 'FINISHED'
    ERROR = 'ERROR'
    SCHEDULED = 'SCHEDULED'
    INTERRUPTED = 'INTERRUPTED'
    OUT_OF_OPERATING_HOURS = 'OUT_OF_OPERATING_HOURS'


class TaskStatus(StrEnum):
    """Platform task status."""
    UNPROCESSED = 'UNPROCESSED'
    VALIDATION_ERROR = 'VALIDATION_ERROR'
    SUCCESS = 'SUCCESS'
    FAIL = 'FAIL'
    RUNNING = 'RUNNING'


class StepStatus(StrEnum):
    """Platform step status."""
    UNPROCESSED = 'UNPROCESSED'
    RUNNING = 'RUNNING'
    SUCCESS = 'SUCCESS'
    FAIL = 'FAIL'


class PlatformObserver(Observer):
    """Observer that sends status updates to the platform."""

    def __init__(
        self,
        server: str,
        secret_key: str,
        instance_id: str,
        verbose: bool = False
    ) -> None:
        """Initialize platform observer.

        Args:
            server (str): Platform server URL.
            secret_key (str): Secret key for authentication.
            instance_id (str): Instance ID for this robot.
            verbose (bool, optional): Enable verbose logging. Defaults to False.
        """
        self.server = server
        self.secret_key = secret_key
        self.instance_id = instance_id
        self.verbose = verbose
        self._client = httpx.Client(
            base_url=f"{server}/automation-gateway/",
            headers={"Authorization": f"Bearer {secret_key}::{instance_id}"},
            timeout=30.0
        )

    def _send_update(self, endpoint: str, data: dict) -> None:
        """Send update to platform.

        Args:
            endpoint (str): API endpoint.
            data (dict): Data to send.
        """
        try:
            response = self._client.post(endpoint, json=data)
            response.raise_for_status()
            if self.verbose:
                logger.debug(f"Platform update sent to {endpoint}: {data}")
        except Exception as e:
            logger.error(f"Failed to send platform update to {endpoint}: {str(e)}")

    def on_execution_start(self, execution_run: ExecutionRun) -> None:
        """Send execution start status.

        Args:
            execution_run (ExecutionRun): The execution run that started.
        """
        self._send_update("/executions", {
            "id": execution_run.id,
            "observation": None,
            "status": ExecutionStatus.RUNNING,
            "endDate": None,
            "totalTaskCount": execution_run.total_tasks,
            "currentTaskCount": execution_run.completed_tasks
        })

    def on_execution_complete(self, execution_run: ExecutionRun) -> None:
        """Send execution complete status.

        Args:
            execution_run (ExecutionRun): The execution run that completed.
        """
        self._send_update("/executions", {
            "id": execution_run.id,
            "observation": None,
            "status": ExecutionStatus.FINISHED,
            "endDate": get_utc_now(),
            "totalTaskCount": execution_run.total_tasks,
            "currentTaskCount": execution_run.completed_tasks
        })

    def on_execution_fail(self, execution_run: ExecutionRun) -> None:
        """Send execution fail status.

        Args:
            execution_run (ExecutionRun): The execution run that failed.
        """
        self._send_update("/executions", {
            "id": execution_run.id,
            "observation": execution_run.error,
            "status": execution_run.status,
            "endDate": get_utc_now(),
            "totalTaskCount": execution_run.total_tasks,
            "currentTaskCount": execution_run.completed_tasks
        })

    def on_execution_update(self, execution_run: ExecutionRun) -> None:
        """Send execution update.

        Args:
            execution_run (ExecutionRun): The execution run that was updated.
        """
        self._send_update("/executions", {
            "id": execution_run.id,
            "observation": None,
            "status": ExecutionStatus.RUNNING,
            "endDate": None,
            "totalTaskCount": execution_run.total_tasks,
            "currentTaskCount": execution_run.completed_tasks
        })

    def on_task_start(self, task_run: TaskRun) -> None:
        """Send task start status.

        Args:
            task_run (TaskRun): The task run that started.
        """
        self._send_update("/tasks", {
            "id": task_run.id,
            "observation": task_run.observation,
            "status": TaskStatus.RUNNING,
            "description": task_run.description,
            "jsonData": {},
            "code": task_run.code,
            "executionId": task_run.execution_run_id,
            "startDate": get_utc_now()
        })

    def on_task_complete(self, task_run: TaskRun) -> None:
        """Send task complete status.

        Args:
            task_run (TaskRun): The task run that completed.
        """
        self._send_update("/tasks", {
            "id": task_run.id,
            "observation": task_run.observation,
            "status": TaskStatus.SUCCESS,
            "endDate": get_utc_now(),
            "description": task_run.description,
            "jsonData": {},
            "code": task_run.code,
            "executionId": task_run.execution_run_id
        })

    def on_task_fail(self, task_run: TaskRun) -> None:
        """Send task fail status.

        Args:
            task_run (TaskRun): The task run that failed.
        """
        self._send_update("/tasks", {
            "id": task_run.id,
            "observation": task_run.error,
            "status": task_run.status,
            "endDate": get_utc_now(),
            "description": task_run.description,
            "jsonData": {},
            "code": task_run.code,
            "executionId": task_run.execution_run_id
        })

    def on_step_start(self, step_run: StepRun) -> None:
        """Send step start status.

        Args:
            step_run (StepRun): The step run that started.
        """
        self._send_update("/taskSteps", {
            "id": step_run.id,
            "observation": step_run.observation,
            "status": StepStatus.RUNNING,
            "taskId": step_run.task_run_id,
            "stepCode": step_run.step_code,
            "startDate": get_utc_now(),
            "automationOnClientId": step_run.automation_on_client_id
        })

    def on_step_complete(self, step_run: StepRun) -> None:
        """Send step complete status.

        Args:
            step_run (StepRun): The step run that completed.
        """
        self._send_update("/taskSteps", {
            "id": step_run.id,
            "observation": step_run.observation,
            "status": StepStatus.SUCCESS,
            "endDate": get_utc_now(),
            "taskId": step_run.task_run_id,
            "stepCode": step_run.step_code,
            "automationOnClientId": step_run.automation_on_client_id
        })

    def on_step_fail(self, step_run: StepRun) -> None:
        """Send step fail status.

        Args:
            step_run (StepRun): The step run that failed.
        """
        self._send_update("/taskSteps", {
            "id": step_run.id,
            "observation": step_run.observation,
            "status": step_run.status,
            "endDate": get_utc_now(),
            "taskId": step_run.task_run_id,
            "stepCode": step_run.step_code,
            "automationOnClientId": step_run.automation_on_client_id
        })

    def close(self) -> None:
        """Close HTTP client."""
        self._client.close()
