"""Play interactive fiction games."""

import pathlib

from mudlib.commands import CommandDefinition, register
from mudlib.embedded_if_session import EmbeddedIFSession
from mudlib.if_session import IFSession, broadcast_to_spectators
from mudlib.player import Player

# Story files directory
_stories_dir = pathlib.Path(__file__).resolve().parents[3] / "content" / "stories"

# Map of game name -> file extension for lookup
_STORY_EXTENSIONS = (".z3", ".z5", ".z8", ".zblorb")


def _find_story(name: str) -> pathlib.Path | None:
    """Find a story file by name in content/stories/."""
    # exact match first
    for ext in _STORY_EXTENSIONS:
        path = _stories_dir / f"{name}{ext}"
        if path.exists():
            return path
    # prefix match (e.g. "zork" matches "zork1.z3")
    if _stories_dir.exists():
        for path in sorted(_stories_dir.iterdir()):
            if path.stem.lower().startswith(name) and path.suffix in _STORY_EXTENSIONS:
                return path
    return None


def _list_stories() -> list[str]:
    """Return available story names."""
    if not _stories_dir.exists():
        return []
    return sorted(
        p.stem for p in _stories_dir.iterdir() if p.suffix in _STORY_EXTENSIONS
    )


async def cmd_play(player: Player, args: str) -> None:
    """Start playing an interactive fiction game."""
    game_name = args.strip().lower()
    if not game_name:
        stories = _list_stories()
        if stories:
            names = ", ".join(stories)
            await player.send(f"play what? available: {names}\r\n")
        else:
            await player.send("play what? (no stories installed)\r\n")
        return

    story_path = _find_story(game_name)
    if not story_path:
        stories = _list_stories()
        if stories:
            names = ", ".join(stories)
            msg = f"no story '{game_name}'. available: {names}\r\n"
        else:
            msg = f"no story found for '{game_name}'.\r\n"
        await player.send(msg)
        return

    # Ensure story_path is a Path object (for mocking compatibility)
    if not isinstance(story_path, pathlib.Path):
        story_path = pathlib.Path(story_path)

    # Use embedded interpreter for z-machine files, dfrotz for others
    if story_path.suffix in (".z3", ".z5", ".z8"):
        try:
            session = EmbeddedIFSession(player, str(story_path), game_name)
        except (FileNotFoundError, OSError) as e:
            await player.send(f"error starting game: {e}\r\n")
            return
    else:
        session = IFSession(player, str(story_path), game_name)

    try:
        intro = await session.start()
    except FileNotFoundError:
        await session.stop()
        await player.send("error: dfrotz not found. cannot play IF games.\r\n")
        return
    except OSError as e:
        await session.stop()
        await player.send(f"error starting game: {e}\r\n")
        return

    player.if_session = session
    player.mode_stack.append("if")

    await player.send("(type ::help for escape commands)\r\n")

    if intro:
        await player.send(intro + "\r\n")
        # Broadcast to spectators
        spectator_msg = f"[{player.name}'s terminal]\r\n{intro}\r\n"
        await broadcast_to_spectators(player, spectator_msg)


register(
    CommandDefinition(
        "play", cmd_play, mode="normal", help="play an interactive fiction game"
    )
)
