"""
Pradhya · NanoClaw Workshop · Unit 07
======================================

A minimal Telegram connector for your NanoClaw-style second brain.

How it works:

    Telegram → long-polling Bot API → this script → nanoclaw_demo.py

The bot accepts two kinds of messages:

    - A URL (or "ingest <url>") triggers the ingest skill.
    - Anything else is treated as a question for the wiki.

Setup:

    1. Talk to @BotFather on Telegram. Run /newbot. Save the token.
    2. Export the token:    export TELEGRAM_TOKEN=...
    3. Export the API key:  export ANTHROPIC_API_KEY=sk-ant-...
    4. Run:                 python telegram_connector.py
    5. Open your bot in Telegram. Send it a URL. Then ask a question.

This is intentionally tiny so you can read it end to end. The real
NanoClaw harness handles webhooks, multi-user, rate limits, etc.
"""

from __future__ import annotations

import io
import os
import sys
import time
import urllib.parse
import urllib.request

from nanoclaw_demo import ingest, query   # local import; same folder


TOKEN = os.environ.get("TELEGRAM_TOKEN")
if not TOKEN:
    sys.exit("Set TELEGRAM_TOKEN. Get one from @BotFather on Telegram.")

API = f"https://api.telegram.org/bot{TOKEN}"


def _http(method: str, **params) -> dict:
    url  = f"{API}/{method}?{urllib.parse.urlencode(params)}"
    with urllib.request.urlopen(url, timeout=60) as r:
        import json
        return json.load(r)


def send(chat_id: int, text: str) -> None:
    # Telegram messages cap at 4096 chars; chunk if needed.
    while text:
        chunk, text = text[:4000], text[4000:]
        _http("sendMessage", chat_id=chat_id, text=chunk)


def looks_like_url(s: str) -> bool:
    return s.startswith(("http://", "https://"))


def handle(chat_id: int, text: str) -> None:
    text = (text or "").strip()
    if not text:
        return

    if looks_like_url(text) or text.startswith("ingest "):
        url = text[7:].strip() if text.startswith("ingest ") else text
        send(chat_id, f"📥 Ingesting {url} ...")
        # capture print() output from the ingest skill into the chat
        out = _capture(lambda: ingest(url))
        send(chat_id, "```\n" + (out[-3500:] if out else "(no output)") + "\n```")
        return

    # Default: treat as a query
    send(chat_id, f"🧠 Thinking about: {text[:200]}")
    out = _capture(lambda: query(text))
    send(chat_id, out or "(no answer)")


def _capture(fn) -> str:
    """Capture stdout from a function call into a string."""
    import contextlib
    buf = io.StringIO()
    with contextlib.redirect_stdout(buf):
        try:
            fn()
        except Exception as e:
            print(f"ERROR: {type(e).__name__}: {e}")
    return buf.getvalue()


def main() -> None:
    print("NanoClaw Telegram connector running. Talk to your bot.")
    offset = 0
    while True:
        try:
            updates = _http("getUpdates", offset=offset, timeout=30)
        except Exception as e:
            print(f"[poll error] {e}")
            time.sleep(5)
            continue

        for upd in updates.get("result", []):
            offset = upd["update_id"] + 1
            msg = upd.get("message")
            if not msg or "text" not in msg:
                continue
            handle(msg["chat"]["id"], msg["text"])


if __name__ == "__main__":
    main()
