"""Admin help topic management commands (@help)."""

from pathlib import Path

from mudlib.commands import CommandDefinition, register
from mudlib.commands.help import _help_topics
from mudlib.content import HelpTopic
from mudlib.editor import Editor
from mudlib.player import Player


async def cmd_at_help(player: Player, args: str) -> None:
    """List all help topics or dispatch to subcommands."""
    args = args.strip()

    parts = args.split(None, 1)
    subcmd = parts[0] if parts else ""
    rest = parts[1] if len(parts) > 1 else ""

    if subcmd == "create":
        await _cmd_create(player, rest)
        return
    if subcmd == "edit":
        await _cmd_edit(player, rest)
        return
    if subcmd == "remove":
        await _cmd_remove(player, rest)
        return

    # Default: list all topics
    if not _help_topics:
        await player.send("No help topics defined.\r\n")
        return

    lines = ["help topics"]
    for name in sorted(_help_topics):
        topic = _help_topics[name]
        admin_tag = " [admin]" if topic.admin else ""
        lines.append(f"  {name:<20} {topic.title}{admin_tag}")
    lines.append("")
    lines.append("  @help create          create a new topic")
    lines.append("  @help edit <topic>    edit an existing topic")
    lines.append("  @help remove <topic>  remove a topic")
    await player.send("\r\n".join(lines) + "\r\n")


async def _cmd_create(player: Player, args: str) -> None:
    """Guided topic creation."""
    if args:
        # Name provided, skip to title prompt
        await _prompt_title(player, name=args)
    else:
        await player.send("topic name: ")
        player.pending_input = _on_name_input


async def _on_name_input(player: Player, line: str) -> None:
    """Handle name input."""
    name = line.strip()
    if not name:
        await player.send("Cancelled.\r\n")
        return
    if name in _help_topics:
        await player.send(f"Topic '{name}' already exists. Use @help edit.\r\n")
        return
    await _prompt_title(player, name=name)


async def _prompt_title(player: Player, name: str) -> None:
    await player.send(f"title [{name}]: ")
    player.pending_input = lambda p, line: _on_title_input(p, line, name)


async def _on_title_input(player: Player, line: str, name: str) -> None:
    title = line.strip() or name
    await player.send("admin only? [y/N]: ")
    player.pending_input = lambda p, line: _on_admin_input(p, line, name, title)


async def _on_admin_input(player: Player, line: str, name: str, title: str) -> None:
    admin = line.strip().lower() in ("y", "yes")
    await _open_body_editor(player, name=name, title=title, admin=admin, body="")


async def _open_body_editor(
    player: Player, name: str, title: str, admin: bool, body: str
) -> None:
    save_cb = _make_help_save_callback(player, name, title, admin)
    player.editor = Editor(
        save_callback=save_cb,
        content_type="text",
        color_depth=player.color_depth or "16",
        initial_content=body,
    )
    player.mode_stack.append("editor")
    await player.send("entering editor for body text. type :h for help.\r\n")


def _make_help_save_callback(player: Player, name: str, title: str, admin: bool):
    async def save_callback(content: str) -> None:
        _write_help_toml(name, title, admin, content)
        _help_topics[name] = HelpTopic(
            name=name, body=content.strip(), title=title, admin=admin
        )
        await player.send(f"help topic '{name}' saved.\r\n")

    return save_callback


def _write_help_toml(name: str, title: str, admin: bool, body: str) -> None:
    """Write a help topic TOML file."""
    help_dir = Path(__file__).resolve().parents[2] / "content" / "help"
    help_dir.mkdir(parents=True, exist_ok=True)
    path = help_dir / f"{name}.toml"

    def _escape(s: str) -> str:
        return s.replace("\\", "\\\\").replace('"', '\\"')

    lines = [f'name = "{_escape(name)}"']
    lines.append(f'title = "{_escape(title)}"')
    if admin:
        lines.append("admin = true")
    lines.append(f'body = """\n{body.strip()}\n"""')
    path.write_text("\n".join(lines) + "\n")


async def _cmd_edit(player: Player, args: str) -> None:
    """Edit an existing help topic."""
    name = args.strip()
    if not name:
        await player.send("Usage: @help edit <topic>\r\n")
        return

    topic = _help_topics.get(name)
    if topic is None:
        await player.send(f"Topic '{name}' not found.\r\n")
        return

    await player.send(f"title [{topic.title}]: ")
    player.pending_input = lambda p, line: _on_edit_title(p, line, name, topic)


async def _on_edit_title(
    player: Player, line: str, name: str, topic: HelpTopic
) -> None:
    title = line.strip() or topic.title
    default = "Y/n" if topic.admin else "y/N"
    await player.send(f"admin only? [{default}]: ")
    player.pending_input = lambda p, line: _on_edit_admin(p, line, name, title, topic)


async def _on_edit_admin(
    player: Player, line: str, name: str, title: str, topic: HelpTopic
) -> None:
    admin = line.strip().lower() in ("y", "yes") if line.strip() else topic.admin
    await _open_body_editor(
        player, name=name, title=title, admin=admin, body=topic.body
    )


async def _cmd_remove(player: Player, args: str) -> None:
    """Remove a help topic."""
    name = args.strip()
    if not name:
        await player.send("Usage: @help remove <topic>\r\n")
        return

    if name not in _help_topics:
        await player.send(f"Topic '{name}' not found.\r\n")
        return

    await player.send(f"Remove topic '{name}'? [y/N]: ")
    player.pending_input = lambda p, line: _on_remove_confirm(p, line, name)


async def _on_remove_confirm(player: Player, line: str, name: str) -> None:
    if line.strip().lower() not in ("y", "yes"):
        await player.send("Cancelled.\r\n")
        return

    # Remove from memory
    _help_topics.pop(name, None)

    # Remove file
    path = Path(__file__).resolve().parents[2] / "content" / "help" / f"{name}.toml"
    if path.exists():
        path.unlink()

    await player.send(f"Topic '{name}' removed.\r\n")


register(
    CommandDefinition(
        "@help", cmd_at_help, admin=True, mode="*", help="manage help topics"
    )
)
