"""Telegram integration — send alerts and run Alive as a Telegram bot.

Two modes:
A) Alert mode: send messages/photos/files to a configured chat.
B) Chat mode: run Alive as a Telegram bot that responds to messages.

Config stored in ~/.alive/config.json:
    {"telegram_token": "...", "telegram_chat_id": "..."}

Usage in skills:

    from alive.integrations.telegram import send_telegram, send_telegram_photo
    send_telegram("Alert: Price dropped to $99!")
    send_telegram_photo("/tmp/screenshot.png", caption="Current view")
"""

from __future__ import annotations

import json
import logging
from typing import Any

_log = logging.getLogger("alive")


# ── Config helpers ──────────────────────────────────────────────────────────


def _load_config() -> dict[str, Any]:
    """Load Alive config."""
    from alive.integrations import _load_config as _cfg

    return _cfg()


def _get_bot_name(token: str) -> str | None:
    """Fetch the bot's username via getMe API."""
    import httpx

    try:
        resp = httpx.get(
            f"https://api.telegram.org/bot{token}/getMe",
            timeout=10,
        )
        resp.raise_for_status()
        data = resp.json()
        if data.get("ok"):
            return f"@{data['result'].get('username', 'unknown')}"
    except Exception as e:
        _log.debug("Failed to get bot name: %s", e)
    return None


# ── Alert mode (simple message sending) ────────────────────────────────────


def send_telegram(message: str) -> bool:
    """Send a text message to the configured Telegram chat.

    Args:
        message: Text message to send (supports Telegram Markdown).

    Returns:
        True if sent successfully.

    Raises:
        ValueError: If Telegram is not configured.
    """
    import httpx

    config = _load_config()
    token = config.get("telegram_token")
    chat_id = config.get("telegram_chat_id")

    if not token or not chat_id:
        raise ValueError(
            "Telegram not configured. Run: alive setup telegram"
        )

    # Truncate if too long for Telegram (4096 char limit)
    if len(message) > 4000:
        message = message[:4000] + "\n\n... (truncated)"

    resp = httpx.post(
        f"https://api.telegram.org/bot{token}/sendMessage",
        json={"chat_id": chat_id, "text": message, "parse_mode": "Markdown"},
        timeout=15,
    )
    resp.raise_for_status()
    data = resp.json()
    return data.get("ok", False)


def send_telegram_photo(photo_path: str, caption: str = "") -> bool:
    """Send a photo to the configured Telegram chat.

    Args:
        photo_path: Path to the image file.
        caption: Optional caption for the photo.

    Returns:
        True if sent successfully.
    """
    import httpx

    config = _load_config()
    token = config.get("telegram_token")
    chat_id = config.get("telegram_chat_id")

    if not token or not chat_id:
        raise ValueError("Telegram not configured. Run: alive setup telegram")

    with open(photo_path, "rb") as f:
        resp = httpx.post(
            f"https://api.telegram.org/bot{token}/sendPhoto",
            data={"chat_id": chat_id, "caption": caption},
            files={"photo": f},
            timeout=30,
        )
    resp.raise_for_status()
    data = resp.json()
    return data.get("ok", False)


def send_telegram_file(file_path: str, caption: str = "") -> bool:
    """Send a file/document to the configured Telegram chat.

    Args:
        file_path: Path to the file to send.
        caption: Optional caption for the document.

    Returns:
        True if sent successfully.
    """
    import httpx

    config = _load_config()
    token = config.get("telegram_token")
    chat_id = config.get("telegram_chat_id")

    if not token or not chat_id:
        raise ValueError("Telegram not configured. Run: alive setup telegram")

    with open(file_path, "rb") as f:
        resp = httpx.post(
            f"https://api.telegram.org/bot{token}/sendDocument",
            data={"chat_id": chat_id, "caption": caption},
            files={"document": f},
            timeout=30,
        )
    resp.raise_for_status()
    data = resp.json()
    return data.get("ok", False)


# ── Chat mode (Telegram bot) ──────────────────────────────────────────────


def start_telegram_bot(token: str | None = None, *, daemon: bool = False) -> None:
    """Start the Alive Telegram bot for interactive chat.

    Args:
        token: Bot token override (defaults to config).
        daemon: If True, fork to background.
    """
    if token is None:
        config = _load_config()
        token = config.get("telegram_token")

    if not token:
        raise ValueError("Telegram not configured. Run: alive setup telegram")

    if daemon:
        _start_daemon(token)
        return

    _run_bot(token)


def _run_bot(token: str) -> None:
    """Run the Telegram bot (blocking)."""
    try:
        from telegram import Update
        from telegram.ext import (
            Application,
            CommandHandler,
            MessageHandler,
            filters,
        )
    except ImportError:
        raise ImportError(
            "python-telegram-bot is required for chat mode.\n"
            "Install: pip install 'alive-agent[telegram]'"
        )

    import asyncio

    async def handle_start(update: Update, context) -> None:
        """Handle the /start command."""
        await update.message.reply_text(
            "🧠 I'm Alive — an AI agent that teaches itself new abilities.\n\n"
            "Just send me any request and I'll figure out how to do it.\n"
            "If I can't, I'll build a new skill for it.\n\n"
            "Try: *What's the current bitcoin price?*",
            parse_mode="Markdown",
        )

    async def handle_message(update: Update, context) -> None:
        """Process a user message through the Alive pipeline."""
        user_text = update.message.text
        chat_id = update.effective_chat.id

        # Send typing indicator
        await context.bot.send_chat_action(chat_id, "typing")

        try:
            # Import and use the planner + composer pipeline
            from alive.core.planner import plan_request
            from alive.core.composer import compose

            plan = await plan_request(user_text)
            result = await compose(plan)
            response = result.final_output

        except Exception as e:
            _log.error("Telegram handler error: %s", e)
            response = f"Sorry, something went wrong: {e}"

        # Truncate for Telegram's 4096 char limit
        if len(response) > 4000:
            response = response[:4000] + "\n\n... (truncated)"

        await update.message.reply_text(response)

    app = Application.builder().token(token).build()
    app.add_handler(CommandHandler("start", handle_start))
    app.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, handle_message))

    _log.info("Starting Telegram bot...")
    app.run_polling()


def _start_daemon(token: str) -> None:
    """Start the Telegram bot as a background daemon."""
    import os
    import subprocess
    import sys

    from alive.config import ALIVE_HOME, LOGS_DIR

    LOGS_DIR.mkdir(parents=True, exist_ok=True)
    pid_file = ALIVE_HOME / "telegram_bot.pid"
    log_file = LOGS_DIR / "telegram_bot.log"

    # Launch as a subprocess
    cmd = [
        sys.executable, "-m", "alive.integrations.telegram",
        "--token", token,
    ]

    with open(log_file, "a") as logf:
        proc = subprocess.Popen(
            cmd,
            stdout=logf,
            stderr=logf,
            start_new_session=True,
        )

    pid_file.write_text(str(proc.pid))
    _log.info("Telegram bot daemon started (PID %d)", proc.pid)


def stop_telegram_bot() -> bool:
    """Stop the Telegram bot daemon. Returns True if stopped."""
    import os
    import signal

    from alive.config import ALIVE_HOME

    pid_file = ALIVE_HOME / "telegram_bot.pid"
    if not pid_file.exists():
        return False

    try:
        pid = int(pid_file.read_text().strip())
        os.kill(pid, signal.SIGTERM)
        pid_file.unlink(missing_ok=True)
        return True
    except (ValueError, ProcessLookupError, OSError):
        pid_file.unlink(missing_ok=True)
        return False


def telegram_status() -> dict[str, Any]:
    """Get Telegram integration status."""
    import os

    from alive.config import ALIVE_HOME

    config = _load_config()
    token = config.get("telegram_token")
    chat_id = config.get("telegram_chat_id")

    status: dict[str, Any] = {
        "configured": bool(token and chat_id),
        "token_set": bool(token),
        "chat_id_set": bool(chat_id),
        "bot_name": None,
        "daemon_running": False,
    }

    if token:
        status["bot_name"] = _get_bot_name(token)

    pid_file = ALIVE_HOME / "telegram_bot.pid"
    if pid_file.exists():
        try:
            pid = int(pid_file.read_text().strip())
            os.kill(pid, 0)
            status["daemon_running"] = True
            status["daemon_pid"] = pid
        except (ValueError, OSError, ProcessLookupError):
            pass

    return status


# ── Setup wizard ───────────────────────────────────────────────────────────


def setup_telegram(console=None) -> bool:
    """Interactive setup wizard for Telegram integration.

    Returns True if setup completed successfully.
    """
    import time

    import httpx
    from rich.console import Console
    from rich.panel import Panel
    from rich.prompt import Prompt

    from alive.integrations import _load_config as _cfg, _save_config

    con = console or Console()

    con.print(Panel(
        "[bold]Let's connect Alive to Telegram[/]\n\n"
        "1. Open Telegram and search for [bold]@BotFather[/]\n"
        "2. Send [bold]/newbot[/] and follow the prompts\n"
        "3. Copy the API token you receive",
        title="[bold cyan]Telegram Setup[/]",
        border_style="cyan",
        padding=(1, 2),
    ))

    # Step 1: Get token
    con.print()
    token = Prompt.ask("[bold]Paste your bot token[/]", console=con)
    token = token.strip()

    if not token:
        con.print("[red]No token provided. Setup cancelled.[/]")
        return False

    # Validate token
    con.print()
    with con.status("[bold cyan]Validating token...", spinner="dots"):
        bot_name = _get_bot_name(token)

    if bot_name:
        con.print(f"[green]✓ Connected to bot: {bot_name}[/]")
    else:
        con.print("[red]✗ Could not validate token. Please check and try again.[/]")
        return False

    # Step 2: Get chat_id
    con.print()
    con.print(
        f"[bold]Now send any message to your bot ({bot_name}) on Telegram,[/]\n"
        "[bold]then press Enter here...[/]"
    )
    Prompt.ask("[dim]Press Enter when ready[/]", default="", console=con)

    # Poll for updates to auto-detect chat_id
    chat_id = None
    with con.status("[bold cyan]Waiting for message...", spinner="dots"):
        try:
            resp = httpx.get(
                f"https://api.telegram.org/bot{token}/getUpdates",
                params={"limit": 5, "timeout": 10},
                timeout=20,
            )
            resp.raise_for_status()
            data = resp.json()

            if data.get("ok") and data.get("result"):
                # Get the most recent message's chat_id
                for update in reversed(data["result"]):
                    msg = update.get("message", {})
                    if msg.get("chat", {}).get("id"):
                        chat_id = str(msg["chat"]["id"])
                        break
        except Exception as e:
            _log.debug("Failed to get updates: %s", e)

    if not chat_id:
        con.print("[yellow]Could not auto-detect chat ID.[/]")
        chat_id = Prompt.ask("[bold]Enter your chat ID manually[/]", console=con)

    if not chat_id:
        con.print("[red]No chat ID. Setup cancelled.[/]")
        return False

    con.print(f"[green]✓ Chat ID detected: {chat_id}[/]")

    # Step 3: Send test message
    con.print()
    with con.status("[bold cyan]Sending test message...", spinner="dots"):
        try:
            resp = httpx.post(
                f"https://api.telegram.org/bot{token}/sendMessage",
                json={
                    "chat_id": chat_id,
                    "text": "🎉 Alive is connected! You'll receive alerts here.",
                },
                timeout=10,
            )
            resp.raise_for_status()
            sent_ok = resp.json().get("ok", False)
        except Exception as e:
            _log.debug("Test message failed: %s", e)
            sent_ok = False

    if sent_ok:
        con.print("[green]✓ Test message sent! Check your Telegram.[/]")
    else:
        con.print("[yellow]⚠ Could not send test message, but config will be saved.[/]")

    # Save config
    cfg = _cfg()
    cfg["telegram_token"] = token
    cfg["telegram_chat_id"] = chat_id
    _save_config(cfg)

    con.print(Panel(
        f"[bold green]Telegram connected![/]\n\n"
        f"Bot: {bot_name}\n"
        f"Chat ID: {chat_id}\n\n"
        f"[dim]Skills can now:[/]\n"
        f"  from alive.integrations.telegram import send_telegram\n"
        f"  send_telegram('Hello from Alive!')\n\n"
        f"[dim]Start chat mode:[/] alive telegram start",
        title="[bold green]Setup Complete[/]",
        border_style="green",
        padding=(1, 2),
    ))
    return True


def test_telegram(console=None) -> bool:
    """Send a test message to verify Telegram integration."""
    from rich.console import Console

    con = console or Console()
    con.print("[bold cyan]Testing Telegram...[/]\n")

    config = _load_config()
    if not config.get("telegram_token"):
        con.print("[red]Telegram not configured. Run: alive setup telegram[/]")
        return False

    try:
        result = send_telegram("🧪 Test message from Alive — integration working!")
        if result:
            con.print("[bold green]✓ Test message sent successfully![/]")
            return True
        else:
            con.print("[bold red]✗ Message sending returned failure.[/]")
            return False
    except Exception as e:
        con.print(f"[bold red]✗ Failed: {e}[/]")
        return False


# ── CLI entry point for daemon ─────────────────────────────────────────────


if __name__ == "__main__":
    import argparse

    parser = argparse.ArgumentParser()
    parser.add_argument("--token", required=True)
    args = parser.parse_args()
    _run_bot(args.token)
