from __future__ import annotations

import html
from typing import Any, Iterable


EMPTY_LABEL = "<code>none</code>"
BOT_COMMAND_SPECS: list[tuple[str, str]] = [
    ("start", "старт и краткая навигация"),
    ("help", "список команд и подсказок"),
    ("openclaw", "запустить агентный запрос"),
    ("status", "карточка текущей сессии"),
    ("provider", "сменить провайдера"),
    ("model", "сменить и сохранить модель"),
    ("providers", "доступные провайдеры"),
    ("models", "модели выбранного провайдера"),
    ("settings", "панель настроек и быстрых действий"),
    ("apikey", "обновить API key провайдера"),
    ("reset", "сбросить текущую сессию"),
    ("end", "закрыть текущую сессию"),
    ("reload", "перезагрузить runtime"),
    ("cancel", "отменить ввод из settings"),
    ("skills", "список skills"),
    ("pair", "pairing и доступ"),
]
_PROVIDER_LABELS = {
    "openai": "OpenAI",
    "openrouter": "OpenRouter",
    "gemini": "Gemini",
    "claude": "Claude",
}


def _escape(value: Any) -> str:
    return html.escape(str(value))



def _code(value: Any) -> str:
    return f"<code>{_escape(value)}</code>"



def _join_codes(values: Iterable[Any]) -> str:
    prepared = [item for item in values if str(item or "").strip()]
    if not prepared:
        return EMPTY_LABEL
    return ", ".join(_code(item) for item in prepared)



def provider_label(name: str) -> str:
    cleaned = str(name or "").strip()
    return _PROVIDER_LABELS.get(cleaned.lower(), cleaned.title() or "Unknown")



def _provider_badges(item: dict[str, Any], *, current_provider: str) -> str:
    bits: list[str] = []
    name = str(item.get("name") or "")
    if name == current_provider:
        bits.append("🟣 current")
    elif item.get("is_default"):
        bits.append("⭐ default")
    else:
        bits.append("⚪ available")
    bits.append("🟢 enabled" if item.get("enabled", True) else "⛔ disabled")
    bits.append("🔐 key set" if item.get("has_api_key") else "🔓 key missing")
    return " · ".join(bits)



def build_help_text() -> str:
    return "\n".join(
        [
            "<b>🤖 OpenClaw Lite — Telegram control panel</b>",
            "<i>Управляй агентом, провайдерами и доступом без копания в YAML.</i>",
            "",
            "<b>🚀 Быстрый старт</b>",
            "• <code>/openclaw [запрос]</code> — запустить агентный запрос",
            "• reply на сообщение бота — продолжить активную задачу",
            "• <code>/status</code> — посмотреть карточку текущей сессии",
            "• <code>/end [session_id]</code> — закрыть сессию",
            "• <code>/reset [session_id]</code> — очистить историю сессии",
            "",
            "<b>🧠 Провайдеры и модели</b>",
            "• <code>/providers</code> — список провайдеров",
            "• <code>/models [provider]</code> — модели провайдера",
            "• <code>/provider [name]</code> — переключить провайдера",
            "• <code>/model [name]</code> — сменить модель и сохранить как default",
            "• <code>/settings</code> — открыть красивую панель настроек",
            "• <code>/apikey [provider] [key]</code> — быстро обновить ключ",
            "",
            "<b>🛠️ Runtime и доступ</b>",
            "• <code>/skills</code> — список skills и их состояние",
            "• <code>/sessions</code> — сохранённые сессии",
            "• <code>/reload</code> — перезагрузить runtime",
            "• <code>/exec [command]</code> — shell-команда (owner only)",
            "• <code>/safe on|off</code> / <code>/mode safe|yolo|god</code> — режим безопасности",
            "• <code>/pair CODE</code> / <code>/approve [user_id] [chat_id]</code> / <code>/auth</code>",
            "",
            "<b>💡 Как бот триггерится</b>",
            "• бот отвечает только на <code>/openclaw</code> или reply на сообщение бота",
            "• auto-continue по active session отключён во всех чатах",
            "• <code>/cancel</code> — отменить ввод, начатый из <code>/settings</code>",
        ]
    )



def build_status_text(status: dict[str, Any]) -> str:
    skills = [item.get("name", "?") for item in (status.get("skills") or [])]
    state = "🟢 active" if not status.get("closed") else "⚪ closed"
    return "\n".join(
        [
            "<b>📍 Session status</b>",
            f"• session: {_code(status.get('session_id', 'unknown'))}",
            f"• provider: {_code(status.get('provider', 'unknown'))}",
            f"• model: {_code(status.get('model', 'unknown'))}",
            f"• mode: {_code(status.get('security_mode', 'safe'))}",
            f"• history: {_code(status.get('history_messages', 0))}",
            f"• state: <b>{state}</b>",
            f"• skills: {_join_codes(skills)}",
        ]
    )



def build_providers_text(providers: list[str]) -> str:
    if not providers:
        return "<b>🧠 Providers</b>\n<i>Провайдеры ещё не настроены.</i>"
    return "\n".join(
        [
            "<b>🧠 Available providers</b>",
            "<i>Переключение: <code>/provider [name]</code></i>",
            *(f"• {_code(provider_label(name))}" for name in providers),
        ]
    )



def build_skills_text(skills: list[dict[str, Any]]) -> str:
    if not skills:
        return "<b>🧩 Skills</b>\n<i>Сейчас нет загруженных skills.</i>"
    lines = ["<b>🧩 Skills</b>"]
    for item in skills:
        enabled = "🟢 on" if item.get("enabled") else "⚪ off"
        name = _code(item.get("name", "?"))
        details = [enabled]
        if item.get("fingerprint"):
            details.append(f"fp={_code(item['fingerprint'])}")
        if item.get("error"):
            details.append(f"error={_code(item['error'])}")
        lines.append(f"• {name} — {' · '.join(details)}")
    return "\n".join(lines)



def build_models_text(models: Any) -> str:
    if isinstance(models, dict):
        lines = ["<b>🧪 Models</b>", "<i>Разбивка по провайдерам.</i>"]
        for provider, items in models.items():
            prepared = items if isinstance(items, list) else [items]
            lines.append(f"• {_code(provider_label(str(provider)))}: {_join_codes(prepared)}")
        return "\n".join(lines)
    if isinstance(models, list):
        return "\n".join(["<b>🧪 Models</b>", f"• {_join_codes(models)}"])
    return "\n".join(["<b>🧪 Models</b>", f"• {_code(models)}"])



def build_sessions_text(items: list[dict[str, Any]]) -> str:
    if not items:
        return "<b>🗂️ Sessions</b>\n<i>Сохранённых сессий пока нет.</i>"
    lines = ["<b>🗂️ Sessions</b>"]
    for item in items:
        state = "🟢 open" if not item.get("closed") else "⚪ closed"
        lines.append(
            "• {}\n  {} / {} · {} · {}".format(
                _code(item.get("session_id", "unknown")),
                _code(provider_label(str(item.get("provider", "?")))),
                _code(item.get("model", "?")),
                _code(item.get("security_mode", "safe")),
                state,
            )
        )
    return "\n".join(lines)



def build_auth_text(payload: dict[str, Any]) -> str:
    pending = payload.get("pairing_codes") or []
    lines = [
        "<b>🔐 Access & Auth</b>",
        f"• owners: {_join_codes(payload.get('owner_user_ids') or [])}",
        f"• owner chats: {_join_codes(payload.get('owner_chat_ids') or [])}",
        f"• allowed users: {_join_codes(payload.get('allowed_user_ids') or [])}",
        f"• allowed chats: {_join_codes(payload.get('allowed_chat_ids') or [])}",
    ]
    if pending:
        lines.append("<b>⏳ Pairing codes</b>")
        for item in pending:
            lines.append(f"• {_code(item.get('code', '?'))} · expires {_code(item.get('expires_at', 'unknown'))}")
    else:
        lines.append("• pairing codes: <i>none pending</i>")
    return "\n".join(lines)



def build_settings_overview(*, session: Any, providers: list[dict[str, Any]]) -> str:
    current_provider = str(getattr(session, "provider", ""))
    lines = [
        "<b>⚙️ LiteClaw Settings</b>",
        "<i>Быстрые кнопки ниже позволяют переключать провайдера, менять ключи и default model без ручной правки конфига.</i>",
        "",
        "<b>🧵 Current session</b>",
        f"• active provider: {_code(provider_label(current_provider))}",
        f"• active model: {_code(getattr(session, 'model', 'unknown'))}",
        f"• mode: {_code(getattr(session, 'security_mode', 'safe'))}",
        "",
        "<b>🧠 Provider overview</b>",
    ]
    for item in providers:
        name = str(item.get("name") or "").strip()
        if not name:
            continue
        lines.append(f"• {_code(provider_label(name))} — {_provider_badges(item, current_provider=current_provider)}")
        lines.append(f"  default model: {_code(item.get('default_model') or 'not set')}")
    lines.extend(
        [
            "",
            "<b>⌨️ Quick commands</b>",
            "• <code>/provider [name]</code> · <code>/model [name]</code>",
            "• <code>/apikey [provider] [key]</code> · <code>/reset</code> · <code>/reload</code>",
        ]
    )
    return "\n".join(lines)



def render_settings_input_prompt(action: str, provider: str) -> str:
    provider_text = _code(provider_label(provider))
    if action == "api_key":
        return (
            f"<b>🔑 Update API key</b>\n"
            f"• provider: {provider_text} <code>({html.escape(provider)})</code>\n"
            "• пришли следующим сообщением новый API key\n"
            "• <code>/cancel</code> — отменить ввод"
        )
    return (
        f"<b>🧠 Update default model</b>\n"
        f"• provider: {provider_text} <code>({html.escape(provider)})</code>\n"
        "• пришли следующим сообщением имя модели\n"
        "• <code>/cancel</code> — отменить ввод"
    )


__all__ = [
    "BOT_COMMAND_SPECS",
    "build_help_text",
    "build_status_text",
    "build_providers_text",
    "build_skills_text",
    "build_models_text",
    "build_sessions_text",
    "build_auth_text",
    "build_settings_overview",
    "provider_label",
    "render_settings_input_prompt",
    "render_status_text",
    "render_providers_text",
    "render_skills_text",
    "render_models_text",
    "render_sessions_text",
    "render_auth_text",
    "render_settings_text",
]

render_status_text = build_status_text
render_providers_text = build_providers_text
render_skills_text = build_skills_text
render_models_text = build_models_text
render_sessions_text = build_sessions_text
render_auth_text = build_auth_text


def render_settings_text(session: Any, providers: list[dict[str, Any]]) -> str:
    return build_settings_overview(session=session, providers=providers)
