"""Telegram gateway setup flow and helpers."""

import re
import time

from armorer.core.prompt_parsing import _extract_reply_value, _is_yes, _is_no, _parse_csv_values
from armorer.core import telegram_experimental_provisioning as tg_exp
from armorer.messaging.telegram import TelegramGateway


def _looks_like_telegram_setup_request(prompt: str) -> bool:
    p = str(prompt or "").strip().lower()
    if "telegram" not in p:
        return False
    setup_terms = ("setup", "set up", "configure", "config", "integration", "connect", "enable", "bot")
    return any(term in p for term in setup_terms)


def _looks_like_question(text: str) -> bool:
    t = str(text or "").strip().lower()
    if not t:
        return False
    if "?" in t:
        return True
    starters = ("how ", "what ", "where ", "which ", "why ", "can i ", "do i ")
    return t.startswith(starters)


def _is_telegram_setup_question(text: str) -> bool:
    t = str(text or "").strip().lower()
    if not t:
        return False
    hints = (
        "telegram",
        "botfather",
        "bot token",
        "token",
        "admin",
        "user id",
        "chat id",
        "alert chat",
        "allowlist",
        "getupdates",
    )
    return any(h in t for h in hints)


def _is_clearly_unrelated_to_telegram_setup(text: str) -> bool:
    t = str(text or "").strip().lower()
    if not t:
        return False
    unrelated_hints = (
        "openclaw",
        "autogpt",
        "clawbot",
        "installed agent",
        "installed agents",
        "what agents",
        "running",
        "status",
        "security scan",
        "threat model",
        "docker logs",
    )
    return any(h in t for h in unrelated_hints)


def _is_clearly_unrelated_to_openclaw_setup(text: str) -> bool:
    t = str(text or "").strip().lower()
    if not t:
        return False
    unrelated_hints = (
        "autogpt",
        "clawbot",
        "installed agent",
        "installed agents",
        "what agents",
        "running",
        "status",
        "security scan",
        "threat model",
        "docker logs",
        "weather",
    )
    return any(h in t for h in unrelated_hints)


def _is_valid_telegram_id(token: str) -> bool:
    # Telegram user/chat IDs are numeric. Groups/channels are often negative
    # and supergroups/channels typically look like -100xxxxxxxxxx.
    return bool(re.fullmatch(r"-?\d{5,20}", str(token or "").strip()))


def _parse_telegram_admin_ids(text: str) -> tuple[list[str], list[str]]:
    valid: list[str] = []
    invalid: list[str] = []
    for token in _parse_csv_values(text):
        if _is_valid_telegram_id(token):
            if token not in valid:
                valid.append(token)
        else:
            invalid.append(token)
    return valid, invalid


def _discover_targets_from_updates(gateway: TelegramGateway) -> list[dict]:
    targets: list[dict] = []
    seen_chat_ids: set[str] = set()
    try:
        updates = gateway.get_updates(timeout=0, allowed_updates=["message", "edited_message", "channel_post"])
    except Exception:
        return targets
    for update in updates:
        if not isinstance(update, dict):
            continue
        message = (
            update.get("message")
            or update.get("edited_message")
            or update.get("channel_post")
            or update.get("edited_channel_post")
        )
        if not isinstance(message, dict):
            continue
        chat = message.get("chat") if isinstance(message.get("chat"), dict) else {}
        sender = message.get("from") if isinstance(message.get("from"), dict) else {}
        chat_id = str(chat.get("id") or "").strip()
        if not chat_id or chat_id in seen_chat_ids or not _is_valid_telegram_id(chat_id):
            continue
        seen_chat_ids.add(chat_id)
        title = str(chat.get("title") or chat.get("username") or chat_id).strip()
        target = {
            "chat_id": chat_id,
            "chat_type": str(chat.get("type") or "").strip(),
            "title": title,
        }
        user_id = str(sender.get("id") or "").strip()
        if user_id and _is_valid_telegram_id(user_id):
            target["user_id"] = user_id
        targets.append(target)
    return targets


def _recommended_ids_from_targets(targets: list[dict]) -> tuple[list[str], str]:
    if not targets:
        return [], ""
    private_target = next((t for t in targets if str(t.get("chat_type") or "").lower() == "private"), targets[0])
    alert_chat = str(private_target.get("chat_id") or "").strip()
    admin_ids: list[str] = []
    if alert_chat and _is_valid_telegram_id(alert_chat):
        admin_ids.append(alert_chat)
    user_id = str(private_target.get("user_id") or "").strip()
    if user_id and _is_valid_telegram_id(user_id) and user_id not in admin_ids:
        admin_ids.append(user_id)
    return admin_ids, alert_chat


def _is_truthy(text: str) -> bool:
    return str(text or "").strip().lower() in {"1", "true", "on", "yes"}


def _apply_token_and_autoconfigure(handler, source: str, conversation_id: str, token: str) -> tuple[str, dict]:
    handler.config_manager.set_armorer_telegram_bot_token(token)
    # Official Bot API can't create bots, but once token is present we can
    # bootstrap IDs from recent updates and reduce manual setup prompts.
    try:
        gateway = TelegramGateway(bot_token=token)
        targets = _discover_targets_from_updates(gateway)
    except Exception:
        targets = []
    admin_ids, alert_chat = _recommended_ids_from_targets(targets)
    if admin_ids:
        csv = ",".join(admin_ids)
        handler.config_manager.set_key("ARMORER_TELEGRAM_ADMIN_USER_IDS", csv)
        handler.config_manager.set_key("ARMORER_TELEGRAM_ADMIN_CHAT_IDS", csv)
        handler.config_manager.set_key("ARMORER_TELEGRAM_ALLOW_UNCONFIGURED_ADMINS", "false")
        if alert_chat:
            handler.config_manager.set_key("TELEGRAM_ALERT_CHAT_ID", alert_chat)
        handler.config_manager.set_key("ARMORER_GATEWAY_TELEGRAM_ENABLED", "true")
        handler._clear_pending_decision(conversation_id)
        message = (
            "Saved TELEGRAM_BOT_TOKEN securely and auto-configured Telegram admin/access settings "
            "from recent bot updates. Telegram configuration is ready."
        )
        if source == "cli":
            return "", {
                "message": message,
                "ui_action": {
                    "type": "interactive_command",
                    "command": "armorer gateway telegram",
                    "reason": "Starts Telegram long-polling gateway in this terminal.",
                },
            }
        return "", {
            "message": f"{message}\nRun `armorer gateway telegram` on the host to begin message polling."
        }
    handler._set_pending_decision(
        conversation_id,
        {"type": "telegram_setup_admins", "created_at": time.time()},
    )
    return "", {
        "message": (
            "Saved TELEGRAM_BOT_TOKEN securely. "
            "Now provide allowed Telegram admin identifiers as comma-separated values "
            "(user IDs and/or chat IDs). Reply `skip` to allow unconfigured admins (less secure)."
        ),
        "ui_action": {
            "type": "text",
            "message": "Enter admin user/chat IDs (comma-separated)",
        },
    }


def _handle_telegram_setup_flow(handler, source: str, conversation_id: str, prompt: str) -> tuple[str, dict | None]:
    raw_prompt = str(prompt or "").strip()
    reply = _extract_reply_value(raw_prompt)
    pending = handler._pending_decisions.get(conversation_id, {})
    pending_type = str(pending.get("type") or "").strip()
    is_setup_intent = _looks_like_telegram_setup_request(raw_prompt)
    is_openclaw_specific = handler._looks_like_openclaw_setup_request(raw_prompt)
    cancel_words = {"cancel", "abort", "stop", "nevermind", "never mind"}
    skip_words = {"skip", "none", "n/a", "na", "-"}
    has_ui_prefix = str(raw_prompt).strip().lower().startswith(("ui input:", "ui selection:", "ui confirmation:"))

    if pending_type.startswith("telegram_setup_"):
        low_reply = str(reply or "").strip().lower()
        if not (has_ui_prefix or is_setup_intent or low_reply in cancel_words):
            return raw_prompt, None

    if pending_type == "openclaw_setup":
        return raw_prompt, None
    if pending_type != "openclaw_setup" and not pending_type.startswith("telegram_setup_") and is_openclaw_specific:
        return raw_prompt, None

    token = str(handler.config_manager.get_armorer_telegram_bot_token() or "").strip()
    admins_users = str(handler.config_manager.get_key("ARMORER_TELEGRAM_ADMIN_USER_IDS") or "").strip()
    admins_chats = str(handler.config_manager.get_key("ARMORER_TELEGRAM_ADMIN_CHAT_IDS") or "").strip()
    allow_unconfigured = str(
        handler.config_manager.get_key("ARMORER_TELEGRAM_ALLOW_UNCONFIGURED_ADMINS")
        or handler.config_manager.get_key("ARMORER_GATEWAY_ALLOW_UNCONFIGURED_ADMINS")
        or "false"
    ).strip().lower() in {"1", "true", "on", "yes"}
    experimental_enabled = _is_truthy(
        handler.config_manager.get_key("ARMORER_TELEGRAM_EXPERIMENTAL_AUTOCREATE") or "false"
    )

    if pending_type == "telegram_setup_creation_mode":
        if _is_no(reply):
            handler._set_pending_decision(
                conversation_id,
                {"type": "telegram_setup_token", "created_at": time.time()},
            )
            return "", {
                "message": "Using official flow. Paste TELEGRAM_BOT_TOKEN from BotFather.",
                "ui_action": {
                    "type": "text",
                    "message": "Paste TELEGRAM_BOT_TOKEN",
                    "sensitive": True,
                },
            }
        if not _is_yes(reply):
            handler._set_pending_decision(
                conversation_id,
                {"type": "telegram_setup_creation_mode", "created_at": time.time()},
            )
            return "", {
                "message": (
                    "Reply `yes` to try experimental bot creation automation, or `no` to use official BotFather token flow."
                ),
                "ui_action": {
                    "type": "confirm",
                    "message": "Try experimental Telegram bot creation automation?",
                    "default": False,
                },
            }
        result = tg_exp.attempt_bot_creation(handler.config_manager)
        token_from_attempt = str(result.get("token") or "").strip()
        if token_from_attempt:
            return _apply_token_and_autoconfigure(handler, source, conversation_id, token_from_attempt)
        handler._set_pending_decision(
            conversation_id,
            {"type": "telegram_setup_token", "created_at": time.time()},
        )
        reason = str(result.get("reason") or "Experimental provisioning did not produce a token.").strip()
        return "", {
            "message": f"{reason}\nContinue with official flow: paste TELEGRAM_BOT_TOKEN.",
            "ui_action": {
                "type": "text",
                "message": "Paste TELEGRAM_BOT_TOKEN",
                "sensitive": True,
            },
        }

    if pending_type == "telegram_setup_token":
        if reply.lower() in cancel_words:
            handler._clear_pending_decision(conversation_id)
            return "", {"message": "Cancelled Telegram setup."}
        if _looks_like_question(reply) and _is_clearly_unrelated_to_telegram_setup(reply):
            return reply, None
        if _looks_like_question(reply):
            handler._set_pending_decision(
                conversation_id,
                {"type": "telegram_setup_token", "created_at": time.time()},
            )
            return "", {
                "message": (
                    "Create a bot via @BotFather in Telegram:\n"
                    "1. Send `/newbot`\n"
                    "2. Choose name + username\n"
                    "3. Copy the token in format `<digits>:<secret>`\n"
                    "Then paste it here."
                ),
                "ui_action": {
                    "type": "text",
                    "message": "Paste TELEGRAM_BOT_TOKEN",
                    "sensitive": True,
                },
            }
        if len(reply) < 20 or ":" not in reply:
            handler._set_pending_decision(
                conversation_id,
                {"type": "telegram_setup_token", "created_at": time.time()},
            )
            return "", {
                "message": (
                    "I need a valid Telegram bot token (typically `<digits>:<secret>`). "
                    "Reply with the token or `cancel`."
                ),
                "ui_action": {
                    "type": "text",
                    "message": "Paste TELEGRAM_BOT_TOKEN",
                    "sensitive": True,
                },
            }
        return _apply_token_and_autoconfigure(handler, source, conversation_id, reply)

    if pending_type == "telegram_setup_admins":
        if reply.lower() in cancel_words:
            handler._clear_pending_decision(conversation_id)
            return "", {"message": "Cancelled Telegram setup."}
        if _looks_like_question(reply) and _is_clearly_unrelated_to_telegram_setup(reply):
            return reply, None
        if reply.lower() in skip_words:
            handler._set_pending_decision(
                conversation_id,
                {"type": "telegram_setup_open_mode_confirm", "created_at": time.time()},
            )
            return "", {
                "message": (
                    "No admin allowlist provided. This reduces security because any chat could issue commands. "
                    "Confirm only if this is a temporary bootstrap step."
                ),
                "ui_action": {
                    "type": "confirm",
                    "message": "Allow unconfigured Telegram admins temporarily?",
                    "default": False,
                },
            }
        if _looks_like_question(reply):
            handler._set_pending_decision(
                conversation_id,
                {"type": "telegram_setup_admins", "created_at": time.time()},
            )
            return "", {
                "message": (
                    "You can get these from Telegram updates once the bot receives a message.\n"
                    "Quick method:\n"
                    "1. Message your bot from the account/chat you want to allow.\n"
                    "2. Open: https://api.telegram.org/bot<YOUR_TOKEN>/getUpdates\n"
                    "3. Use `from.id` (user ID) and `chat.id` (chat ID).\n"
                    "Then paste IDs as comma-separated numbers (example: `123456789,-1001234567890`)."
                ),
                "ui_action": {
                    "type": "text",
                    "message": "Enter admin user/chat IDs (comma-separated)",
                },
            }

        ids, invalid = _parse_telegram_admin_ids(reply)
        if not ids or invalid:
            handler._set_pending_decision(
                conversation_id,
                {"type": "telegram_setup_admins", "created_at": time.time()},
            )
            invalid_note = f" Invalid values: {', '.join(invalid[:5])}." if invalid else ""
            return "", {
                "message": (
                    "Please provide numeric Telegram user/chat IDs, comma-separated."
                    f"{invalid_note} Example: `123456789,-1001234567890`."
                ),
                "ui_action": {
                    "type": "text",
                    "message": "Enter admin user/chat IDs (comma-separated)",
                },
            }
        csv = ",".join(ids)
        handler.config_manager.set_key("ARMORER_TELEGRAM_ADMIN_USER_IDS", csv)
        handler.config_manager.set_key("ARMORER_TELEGRAM_ADMIN_CHAT_IDS", csv)
        handler.config_manager.set_key("ARMORER_TELEGRAM_ALLOW_UNCONFIGURED_ADMINS", "false")
        handler._set_pending_decision(
            conversation_id,
            {"type": "telegram_setup_alert_chat", "created_at": time.time()},
        )
        return "", {
            "message": (
                "Saved Telegram admin allowlist. "
                "Optional: provide TELEGRAM_ALERT_CHAT_ID for guard alerts, or reply `skip`."
            ),
            "ui_action": {
                "type": "text",
                "message": "Enter TELEGRAM_ALERT_CHAT_ID (or `skip`)",
            },
        }

    if pending_type == "telegram_setup_open_mode_confirm":
        if _looks_like_question(reply) and _is_clearly_unrelated_to_telegram_setup(reply):
            return reply, None
        if _is_no(reply):
            handler._set_pending_decision(
                conversation_id,
                {"type": "telegram_setup_admins", "created_at": time.time()},
            )
            return "", {
                "message": "Understood. Provide admin user/chat IDs so we keep secure defaults.",
                "ui_action": {
                    "type": "text",
                    "message": "Enter admin user/chat IDs (comma-separated)",
                },
            }
        if not _is_yes(reply):
            handler._set_pending_decision(
                conversation_id,
                {"type": "telegram_setup_open_mode_confirm", "created_at": time.time()},
            )
            return "", {
                "message": "Reply `yes` to allow unconfigured admins temporarily, or `no` to provide allowlist IDs.",
                "ui_action": {
                    "type": "confirm",
                    "message": "Allow unconfigured Telegram admins temporarily?",
                    "default": False,
                },
            }
        handler.config_manager.set_key("ARMORER_TELEGRAM_ALLOW_UNCONFIGURED_ADMINS", "true")
        handler._set_pending_decision(
            conversation_id,
            {"type": "telegram_setup_alert_chat", "created_at": time.time()},
        )
        return "", {
            "message": "Temporary open-admin mode enabled. Optional: provide TELEGRAM_ALERT_CHAT_ID, or reply `skip`.",
            "ui_action": {
                "type": "text",
                "message": "Enter TELEGRAM_ALERT_CHAT_ID (or `skip`)",
            },
        }

    if pending_type == "telegram_setup_alert_chat":
        if reply.lower() in cancel_words:
            handler._clear_pending_decision(conversation_id)
            return "", {"message": "Cancelled Telegram setup."}
        if _looks_like_question(reply) and _is_clearly_unrelated_to_telegram_setup(reply):
            return reply, None
        if _looks_like_question(reply):
            handler._set_pending_decision(
                conversation_id,
                {"type": "telegram_setup_alert_chat", "created_at": time.time()},
            )
            return "", {
                "message": (
                    "`TELEGRAM_ALERT_CHAT_ID` is where guard/security alerts are sent. "
                    "Use your private chat ID or an ops group chat ID, or reply `skip`."
                ),
                "ui_action": {
                    "type": "text",
                    "message": "Enter TELEGRAM_ALERT_CHAT_ID (or `skip`)",
                },
            }
        if not str(reply or "").strip():
            handler._set_pending_decision(
                conversation_id,
                {"type": "telegram_setup_alert_chat", "created_at": time.time()},
            )
            return "", {
                "message": "Enter TELEGRAM_ALERT_CHAT_ID or reply `skip` to continue without a dedicated alert chat.",
                "ui_action": {
                    "type": "text",
                    "message": "Enter TELEGRAM_ALERT_CHAT_ID (or `skip`)",
                },
            }
        if reply.lower() not in skip_words and reply:
            if not _is_valid_telegram_id(reply):
                handler._set_pending_decision(
                    conversation_id,
                    {"type": "telegram_setup_alert_chat", "created_at": time.time()},
                )
                return "", {
                    "message": "TELEGRAM_ALERT_CHAT_ID must be a numeric Telegram chat ID. Example: `-1001234567890`.",
                    "ui_action": {
                        "type": "text",
                        "message": "Enter TELEGRAM_ALERT_CHAT_ID (or `skip`)",
                    },
                }
            handler.config_manager.set_key("TELEGRAM_ALERT_CHAT_ID", reply)
        handler.config_manager.set_key("ARMORER_GATEWAY_TELEGRAM_ENABLED", "true")
        handler._clear_pending_decision(conversation_id)
        msg = "Telegram configuration saved. Gateway can now be started."
        if source == "cli":
            return "", {
                "message": msg,
                "ui_action": {
                    "type": "interactive_command",
                    "command": "armorer gateway telegram",
                    "reason": "Starts Telegram long-polling gateway in this terminal.",
                },
            }
        return "", {
            "message": (
                f"{msg}\nRun `armorer gateway telegram` on the host to begin message polling."
            )
        }

    if not is_setup_intent:
        return raw_prompt, None

    if not token:
        if experimental_enabled:
            handler._set_pending_decision(
                conversation_id,
                {"type": "telegram_setup_creation_mode", "created_at": time.time()},
            )
            return "", {
                "message": (
                    "Experimental Telegram bot creation mode is enabled for this environment. "
                    "Try it first, or continue with the official BotFather flow."
                ),
                "ui_action": {
                    "type": "confirm",
                    "message": "Try experimental Telegram bot creation automation?",
                    "default": False,
                },
            }
        handler._set_pending_decision(
            conversation_id,
            {"type": "telegram_setup_token", "created_at": time.time()},
        )
        return "", {
            "message": (
                "I can configure Telegram for Armorer-managed assistants. "
                "First I need your Telegram bot token."
            ),
            "ui_action": {
                "type": "text",
                "message": "Paste TELEGRAM_BOT_TOKEN",
                "sensitive": True,
            },
        }

    if not (admins_users or admins_chats or allow_unconfigured):
        handler._set_pending_decision(
            conversation_id,
            {"type": "telegram_setup_admins", "created_at": time.time()},
        )
        return "", {
            "message": (
                "Telegram token is already configured. "
                "Now provide admin user/chat IDs to enforce secure access control."
            ),
            "ui_action": {
                "type": "text",
                "message": "Enter admin user/chat IDs (comma-separated)",
            },
        }

    handler._set_pending_decision(
        conversation_id,
        {"type": "telegram_setup_alert_chat", "created_at": time.time()},
    )
    return "", {
        "message": (
            "Telegram token and access policy are already configured. "
            "Optional: set TELEGRAM_ALERT_CHAT_ID, or reply `skip` to start gateway now."
        ),
        "ui_action": {
            "type": "text",
            "message": "Enter TELEGRAM_ALERT_CHAT_ID (or `skip`)",
        },
    }
