"""Satellite tracking tools — search, passes, visible targets."""

from dataclasses import asdict

from fastmcp import Context

from mcbirdcage.state import BirdcageState


def _require_craft(state: BirdcageState):
    if state.craft_client is None:
        raise RuntimeError("No Craft API client configured.")


def register(mcp):
    """Register satellite tools on the FastMCP instance."""

    @mcp.tool()
    async def search_satellites(
        ctx: Context,
        query: str,
        limit: int = 20,
    ) -> dict:
        """Search the orbital object catalog for satellites, planets, and stars.

        Uses the Craft API (space.warehack.ing) to find objects by name.
        Returns matches with name, type, NORAD ID (for satellites), and
        current altitude if above horizon.

        Args:
            query: Search term (e.g. "ISS", "NOAA", "Moon").
            limit: Maximum results to return.
        """
        state: BirdcageState = ctx.request_context.lifespan_context
        _require_craft(state)
        results = state.craft_client.search(query, limit)
        return {
            "results": [asdict(r) for r in results],
            "count": len(results),
        }

    @mcp.tool()
    async def get_passes(
        ctx: Context,
        norad_id: int,
        hours: int = 24,
    ) -> dict:
        """Get upcoming pass predictions for a satellite.

        Returns AOS/TCA/LOS times, azimuths, max elevation, duration,
        and visibility for each predicted pass.

        Args:
            norad_id: NORAD catalog number (e.g. 25544 for ISS).
            hours: How many hours ahead to predict (default 24).
        """
        state: BirdcageState = ctx.request_context.lifespan_context
        _require_craft(state)
        passes = state.craft_client.get_passes(norad_id, hours)
        return {
            "passes": [asdict(p) for p in passes],
            "count": len(passes),
        }

    @mcp.tool()
    async def get_next_pass(ctx: Context, norad_id: int) -> dict:
        """Get the next upcoming pass for a satellite.

        Returns the single soonest pass prediction, or null if none
        are predicted in the near future.

        Args:
            norad_id: NORAD catalog number (e.g. 25544 for ISS).
        """
        state: BirdcageState = ctx.request_context.lifespan_context
        _require_craft(state)
        p = state.craft_client.get_next_pass(norad_id)
        if p is None:
            return {"pass": None}
        return {"pass": asdict(p)}

    @mcp.tool()
    async def get_visible_targets(
        ctx: Context,
        min_alt: float = 0.0,
    ) -> dict:
        """Get all objects currently above the horizon with real-time positions.

        Returns satellites, planets, and stars with AZ/EL computed
        server-side. This is the primary tracking endpoint — use it
        to find what's overhead right now.

        Args:
            min_alt: Minimum altitude in degrees (default 0 = horizon).
        """
        state: BirdcageState = ctx.request_context.lifespan_context
        _require_craft(state)
        targets = state.craft_client.get_visible_targets(min_alt)
        return {
            "targets": [asdict(t) for t in targets],
            "count": len(targets),
        }
