"""Task delegation data model and HTTP client for hub-routed task delegation."""

from __future__ import annotations

import json
import time
import urllib.request
import uuid
from dataclasses import asdict, dataclass, field

# Task states
PENDING = "pending"
ASSIGNED = "assigned"
RUNNING = "running"
COMPLETED = "completed"
FAILED = "failed"


@dataclass
class Task:
    """A unit of work delegated between agents via the hub."""

    id: str = ""
    skill: str = ""  # target skill name ("" if routing by agent_id)
    target_agent_id: str = ""  # "" for skill-based routing
    source_agent_id: str = ""  # who submitted the task
    payload: dict = field(default_factory=dict)  # {"message": "...", "args": {...}}
    state: str = PENDING
    assigned_agent_id: str = ""
    result: str = ""
    error: str = ""
    created_at: float = 0.0
    updated_at: float = 0.0
    ttl: int = 300  # seconds before auto-fail

    def to_dict(self) -> dict:
        return asdict(self)

    @classmethod
    def from_dict(cls, data: dict) -> Task:
        known = {f.name for f in cls.__dataclass_fields__.values()}
        return cls(**{k: v for k, v in data.items() if k in known})

    @classmethod
    def new(
        cls,
        skill: str,
        payload: dict,
        source_agent_id: str,
        target_agent_id: str = "",
        ttl: int = 300,
    ) -> Task:
        now = time.time()
        return cls(
            id=uuid.uuid4().hex[:12],
            skill=skill,
            target_agent_id=target_agent_id,
            source_agent_id=source_agent_id,
            payload=payload,
            state=PENDING,
            created_at=now,
            updated_at=now,
            ttl=ttl,
        )


class TaskClient:
    """Agent-side HTTP client for hub task endpoints.  Stdlib-only."""

    def __init__(self, hub_url: str) -> None:
        self._base = hub_url.rstrip("/")

    def _post(self, path: str, data: dict) -> dict:
        body = json.dumps(data).encode()
        req = urllib.request.Request(
            f"{self._base}{path}",
            data=body,
            headers={"Content-Type": "application/json"},
            method="POST",
        )
        try:
            with urllib.request.urlopen(req, timeout=10) as resp:
                return json.loads(resp.read().decode())
        except Exception:
            return {}

    def _patch(self, path: str, data: dict) -> dict:
        body = json.dumps(data).encode()
        req = urllib.request.Request(
            f"{self._base}{path}",
            data=body,
            headers={"Content-Type": "application/json"},
            method="PATCH",
        )
        try:
            with urllib.request.urlopen(req, timeout=10) as resp:
                return json.loads(resp.read().decode())
        except Exception:
            return {}

    def _get(self, path: str) -> dict:
        req = urllib.request.Request(f"{self._base}{path}", method="GET")
        try:
            with urllib.request.urlopen(req, timeout=10) as resp:
                return json.loads(resp.read().decode())
        except Exception:
            return {}

    def submit(
        self,
        skill: str,
        payload: dict,
        source_agent_id: str,
        target_agent_id: str = "",
        ttl: int = 300,
    ) -> str:
        """Submit a task to the hub. Returns the task ID or empty string on failure."""
        resp = self._post(
            "/api/hub/tasks",
            {
                "skill": skill,
                "payload": payload,
                "source_agent_id": source_agent_id,
                "target_agent_id": target_agent_id,
                "ttl": ttl,
            },
        )
        return resp.get("task_id", "")

    def update_status(
        self,
        task_id: str,
        state: str,
        result: str = "",
        error: str = "",
    ) -> None:
        """Report task completion or failure back to the hub."""
        self._patch(
            f"/api/hub/tasks/{task_id}",
            {
                "state": state,
                "result": result,
                "error": error,
            },
        )

    def get_result(self, task_id: str) -> dict:
        """Poll for a task's current state and result."""
        return self._get(f"/api/hub/tasks/{task_id}")
