"""Der einzige Befehlsparser des Kerns.

- /start, /help, /status gehören dem Telegram-Plugin (Pairing-Semantik).
  Das Gateway fängt sie nicht ab und leitet sie nie an ein Modell.
- /auto, /codex, /claude ohne Text setzen den Modus des Chats dauerhaft.
- /codex <Text> (bzw. /claude, /auto) gilt nur für diese eine Nachricht.
- Jeder andere /-Befehl ist eine normale Nachricht (heutiges Verhalten:
  das Plugin reicht ihn an Claude weiter), läuft also durch die Policy.

Ob ein Absender Modusbefehle geben darf, entscheidet NICHT der Parser,
sondern das Gateway (nur authentifizierte Besitzer, siehe gateway.py).
"""
from __future__ import annotations

import re
from dataclasses import dataclass
from enum import Enum
from typing import Optional

from .core import Mode


class CommandKind(str, Enum):
    MESSAGE = "message"
    SET_MODE = "set_mode"
    ONE_SHOT = "one_shot"
    PLUGIN_OWNED = "plugin_owned"


PLUGIN_OWNED_COMMANDS = frozenset({"/start", "/help", "/status"})
MODE_COMMANDS = {"/auto": Mode.AUTO, "/codex": Mode.CODEX, "/claude": Mode.CLAUDE}
_HEAD = re.compile(r"^(\S+)(?:\s+([\s\S]*))?$")


@dataclass(frozen=True)
class ParsedCommand:
    kind: CommandKind
    text: str = ""
    mode: Optional[Mode] = None
    command: Optional[str] = None


def parse_command(message: str, *, bot_username: Optional[str] = None) -> ParsedCommand:
    if not isinstance(message, str):
        raise ValueError("INVALID_MESSAGE")
    stripped = message.strip()
    if not stripped.startswith("/"):
        return ParsedCommand(CommandKind.MESSAGE, text=message)
    match = _HEAD.match(stripped)
    head = match.group(1) if match else stripped
    rest = (match.group(2) or "") if match else ""
    name = head.lower()
    if "@" in name:
        name, _, target = name.partition("@")
        if bot_username is not None and target != bot_username.lower():
            # Befehl an einen anderen Bot: normale Nachricht.
            return ParsedCommand(CommandKind.MESSAGE, text=message)
    if name in PLUGIN_OWNED_COMMANDS:
        return ParsedCommand(CommandKind.PLUGIN_OWNED, command=name)
    if name in MODE_COMMANDS:
        mode = MODE_COMMANDS[name]
        if rest.strip():
            return ParsedCommand(CommandKind.ONE_SHOT, text=rest.strip(), mode=mode, command=name)
        return ParsedCommand(CommandKind.SET_MODE, mode=mode, command=name)
    return ParsedCommand(CommandKind.MESSAGE, text=message, command=name)
