"""Cooldown helpers for the Artifacts SDK."""

from __future__ import annotations

import asyncio
import functools
import logging
from typing import Any, Callable, TypeVar

from .models.common import CooldownSchema

logger = logging.getLogger("artifacts.cooldown")

F = TypeVar("F", bound=Callable[..., Any])


async def wait_for_cooldown(cooldown: CooldownSchema) -> None:
    """Sleep for the remaining cooldown duration.

    Call this explicitly after an action if you want to wait::

        result = await char.fight()
        await wait_for_cooldown(result.cooldown)

    .. note::

       When ``auto_wait`` is enabled (the default), the SDK calls
       this automatically.  You only need to call it manually when
       ``auto_wait`` is disabled.
    """
    if cooldown.remaining_seconds > 0:
        await asyncio.sleep(cooldown.remaining_seconds)


def cooldown_seconds(cooldown: CooldownSchema) -> int:
    """Return the remaining seconds from a cooldown."""
    return cooldown.remaining_seconds


def _auto_cooldown(method: F) -> F:
    """Decorator: automatically waits for cooldown after an action.

    Reads ``self._auto_wait`` to decide.  Can be overridden per-call
    via a ``wait`` keyword argument::

        await char.fight()              # auto-waits (default)
        await char.fight(wait=False)    # returns immediately
    """

    @functools.wraps(method)
    async def wrapper(self: Any, *args: Any, **kwargs: Any) -> Any:
        # Extract per-call override
        wait = kwargs.pop("wait", None)
        should_wait = wait if wait is not None else self._auto_wait

        result = await method(self, *args, **kwargs)

        if should_wait and hasattr(result, "cooldown"):
            cd = result.cooldown
            if cd.remaining_seconds > 0:
                logger.debug(
                    "Auto-waiting %ds cooldown for %s.%s",
                    cd.remaining_seconds,
                    type(self).__name__,
                    method.__name__,
                )
                await asyncio.sleep(cd.remaining_seconds)

        return result

    return wrapper  # type: ignore[return-value]
