"""
Models for execution tracking.
"""
from dataclasses import dataclass, field
from datetime import datetime
from enum import StrEnum
from typing import Any, Optional
from uuid_extensions import uuid7str


class ExecutionStatus(StrEnum):
    """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):
    """Task status."""
    SUCCESS = 'SUCCESS'
    FAIL = 'FAIL'
    RUNNING = 'RUNNING'


class StepStatus(StrEnum):
    """Step status."""
    RUNNING = 'RUNNING'
    SUCCESS = 'SUCCESS'
    FAIL = 'FAIL'


@dataclass
class ExecutionRun:
    """Represents a single execution run."""
    id: str = field(default_factory=uuid7str)
    name: str = ""
    status: ExecutionStatus = ExecutionStatus.WAITING
    start_time: Optional[datetime] = None
    end_time: Optional[datetime] = None
    error: Optional[str] = None
    metadata: dict[str, Any] = field(default_factory=dict)
    total_tasks: int = 0
    completed_tasks: int = 0

    @property
    def duration(self) -> Optional[float]:
        """Get duration in seconds.

        Returns:
            Optional[float]: Duration in seconds or None if not completed.
        """
        if self.start_time and self.end_time:
            return (self.end_time - self.start_time).total_seconds()
        return None

    @property
    def progress(self) -> float:
        """Get progress percentage.

        Returns:
            float: Progress percentage (0-100).
        """
        if self.total_tasks == 0:
            return 0.0
        return (self.completed_tasks / self.total_tasks) * 100

    def to_dict(self) -> dict[str, Any]:
        """Convert to dict format compatible with API.

        Returns:
            dict[str, Any]: Dictionary representation for API.
        """
        return {
            'id': self.id,
            'observation': self.error,
            'status': self.status,
            'endDate': self.end_time.isoformat() if self.end_time else None,
            'startDate': self.start_time.isoformat() if self.start_time else None,
            'totalTaskCount': self.total_tasks,
            'currentTaskCount': self.completed_tasks,
        }


@dataclass
class TaskRun:
    """Represents a single task run."""
    id: str = field(default_factory=uuid7str)
    name: str = ""
    execution_run_id: Optional[str] = None
    status: TaskStatus = TaskStatus.RUNNING
    start_time: Optional[datetime] = None
    end_time: Optional[datetime] = None
    error: Optional[str] = None
    metadata: dict[str, Any] = field(default_factory=dict)
    description: Optional[str] = None
    code: Optional[str] = None
    observation: Optional[str] = None
    json_data: dict[str, Any] = field(default_factory=dict)
    total_steps: int = 0
    completed_steps: int = 0
    failed_steps: int = 0

    @property
    def duration(self) -> Optional[float]:
        """Get duration in seconds.

        Returns:
            Optional[float]: Duration in seconds or None if not completed.
        """
        if self.start_time and self.end_time:
            return (self.end_time - self.start_time).total_seconds()
        return None

    @property
    def progress(self) -> float:
        """Get progress percentage.

        Returns:
            float: Progress percentage (0-100).
        """
        if self.total_steps == 0:
            return 0.0
        return (self.completed_steps / self.total_steps) * 100

    def to_dict(self) -> dict[str, Any]:
        """Convert to dict format compatible with API.

        Returns:
            dict[str, Any]: Dictionary representation for API.
        """
        return {
            'id': self.id,
            'observation': self.error,
            'status': self.status,
            'endDate': self.end_time.isoformat() if self.end_time else None,
            'startDate': self.start_time.isoformat() if self.start_time else None,
            'description': self.description or self.name,
            'jsonData': self.json_data,
            'code': self.code,
            'executionId': self.execution_run_id,
        }


@dataclass
class StepRun:
    """Represents a single step run."""
    id: str = field(default_factory=uuid7str)
    name: str = ""
    task_run_id: Optional[str] = None
    status: StepStatus = StepStatus.RUNNING
    start_time: Optional[datetime] = None
    end_time: Optional[datetime] = None
    error: Optional[str] = None
    metadata: dict[str, Any] = field(default_factory=dict)
    step_code: Optional[str] = None
    observation: Optional[str] = None
    automation_on_client_id: Optional[str] = None

    @property
    def duration(self) -> Optional[float]:
        """Get duration in seconds.

        Returns:
            Optional[float]: Duration in seconds or None if not completed.
        """
        if self.start_time and self.end_time:
            return (self.end_time - self.start_time).total_seconds()
        return None

    def to_dict(self) -> dict[str, Any]:
        """Convert to dict format compatible with API.

        Returns:
            dict[str, Any]: Dictionary representation for API.
        """
        return {
            'id': self.id,
            'observation': self.error,
            'status': self.status,
            'endDate': self.end_time.isoformat() if self.end_time else None,
            'startDate': self.start_time.isoformat() if self.start_time else None,
            'taskId': self.task_run_id,
            'stepCode': self.step_code or self.name,
            'automationOnClientId': self.automation_on_client_id,
        }


@dataclass
class Execution:
    """Execution definition."""
    name: str
    description: Optional[str] = None
    version: Optional[str] = None
    tags: list[str] = field(default_factory=list)


@dataclass
class Task:
    """Task definition."""
    name: str
    description: Optional[str] = None
    retries: int = 0
    tags: list[str] = field(default_factory=list)


@dataclass
class Step:
    """Step definition."""
    name: str
    description: Optional[str] = None
    tags: list[str] = field(default_factory=list)
