"""Fly command for aerial movement across the world."""

from mudlib.commands import CommandDefinition, register
from mudlib.commands.movement import DIRECTIONS, send_nearby_message
from mudlib.effects import add_effect
from mudlib.player import Player
from mudlib.render.ansi import BOLD, BRIGHT_WHITE
from mudlib.zone import Zone

# how far you fly
FLY_DISTANCE = 5

# origin cloud gets the base ttl, each step toward destination adds stagger.
# trail visibly shrinks from origin toward the player, one tile at a time.
CLOUD_TTL = 1.5
CLOUD_STAGGER = 0.4  # seconds between each cloud's expiry

# ANSI color for cloud trails
CLOUD_COLOR = BOLD + BRIGHT_WHITE


async def cmd_fly(player: Player, args: str) -> None:
    """Toggle flying or move while airborne.

    fly        - toggle flying on/off
    fly <dir>  - move 5 tiles in a direction (must be flying)
    """
    direction = args.strip().lower()

    # no args = toggle flying state
    if not direction:
        if player.flying:
            player.flying = False
            player.writer.write("You land.\r\n")
            await player.writer.drain()
            await send_nearby_message(
                player,
                player.x,
                player.y,
                f"{player.name} lands.\r\n",
            )
        else:
            player.flying = True
            player.writer.write("You fly into the air!\r\n")
            await player.writer.drain()
            await send_nearby_message(
                player,
                player.x,
                player.y,
                f"{player.name} lifts into the air!\r\n",
            )
        return

    # direction given but not flying
    if not player.flying:
        player.writer.write("You aren't flying.\r\n")
        await player.writer.drain()
        return

    delta = DIRECTIONS.get(direction)
    if delta is None:
        player.writer.write(f"'{direction}' isn't a direction.\r\n")
        await player.writer.drain()
        return

    zone = player.location
    assert isinstance(zone, Zone), "Player must be in a zone to fly"

    dx, dy = delta
    start_x, start_y = player.x, player.y

    # lay cloud trail at starting position and each intermediate step.
    # origin cloud expires first, near-dest cloud lingers longest.
    # the trail shrinks from behind toward the player over time.
    for step in range(FLY_DISTANCE):
        trail_x, trail_y = zone.wrap(start_x + dx * step, start_y + dy * step)
        ttl = CLOUD_TTL + step * CLOUD_STAGGER
        add_effect(trail_x, trail_y, "~", CLOUD_COLOR, ttl=ttl)

    # move player to destination
    dest_x, dest_y = zone.wrap(start_x + dx * FLY_DISTANCE, start_y + dy * FLY_DISTANCE)
    player.x = dest_x
    player.y = dest_y

    # auto-look at new position
    from mudlib.commands.look import cmd_look

    await cmd_look(player, "")


register(CommandDefinition("fly", cmd_fly))
