"""Telegram notification integration for opendeviationbar-py.

This module provides Telegram notifications for hook events, enabling
"loud" alerts for failures and successes during cache operations.

Configuration
-------------
Set environment variables (via Doppler or .env):

    OPENDEVIATIONBAR_TELEGRAM_TOKEN - Bot token from @BotFather
    OPENDEVIATIONBAR_TELEGRAM_CHAT_ID - Your chat ID (send /start to bot to get it)

Or use Doppler:
    doppler secrets set OPENDEVIATIONBAR_TELEGRAM_TOKEN \
        --project opendeviationbar --config prd
    doppler secrets set OPENDEVIATIONBAR_TELEGRAM_CHAT_ID \
        --project opendeviationbar --config prd

Usage
-----
>>> from opendeviationbar.notify.telegram import enable_telegram_notifications
>>> enable_telegram_notifications()
>>> # All hook events will now be sent to Telegram

Or selective registration for failures only:
>>> from opendeviationbar.notify.telegram import telegram_notify
>>> from opendeviationbar.hooks import register_for_failures
>>> register_for_failures(telegram_notify)
"""

from __future__ import annotations

import json
import logging
import os
import socket
import time
from functools import lru_cache
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from ..hooks import HookPayload

logger = logging.getLogger(__name__)

# Issue #117-119: Module-level start time for uptime tracking
_MODULE_START_TIME: float = time.monotonic()

# Default chat ID (Terry Li @EonLabsOperations) - can be overridden via env
# SSoT-OK: This is a Telegram chat ID, not a version number
_DEFAULT_CHAT_ID = "90417581"


def set_start_time(t: float) -> None:
    """Set the module-level start time (call from sidecar/kintsugi startup)."""
    global _MODULE_START_TIME  # noqa: PLW0603
    _MODULE_START_TIME = t


def _build_context_block(service: str) -> str:
    """Build standardized context block for Telegram messages (Issue #117-119).

    Every Telegram alert includes host, version, and uptime so the operator
    can diagnose without SSH-ing in.
    """
    host = socket.gethostname()
    try:
        import opendeviationbar

        version = opendeviationbar.__version__
    except (ImportError, AttributeError):
        version = "?"
    elapsed = time.monotonic() - _MODULE_START_TIME
    days, rem = divmod(int(elapsed), 86400)
    hours, rem = divmod(rem, 3600)
    mins = rem // 60
    uptime = f"{days}d {hours}h {mins}m"
    # Issue #126: Include ouroboros mode for operational awareness
    try:
        from opendeviationbar.ouroboros import get_operational_ouroboros_mode

        mode = get_operational_ouroboros_mode()
    except (ImportError, ValueError, OSError):
        mode = "?"
    # Issue #128: Feature toggle state for operational visibility
    try:
        from opendeviationbar.config import Settings

        pop = Settings.get().population
        t2 = "ON" if pop.compute_tier2 else "OFF"
        t3 = "ON" if pop.compute_tier3 else "OFF"
        hurst = "ON" if pop.compute_hurst else "OFF"
        pe = "ON" if pop.compute_permutation_entropy else "OFF"
        tiers = f"T1+T2 {t2} | T3 {t3} | Hurst {hurst} | PE {pe}"
    except (ImportError, ValueError, OSError):
        tiers = "?"
    return (
        f"\n\n<b>Host:</b> {host} | <b>v</b>{version}"
        f"\n<b>Uptime:</b> {uptime} | <b>Service:</b> {service}"
        f"\n<b>Ouroboros:</b> {mode}"
        f"\n<b>Tiers:</b> {tiers}"
    )


@lru_cache(maxsize=1)
def get_telegram_config() -> dict[str, str | None]:
    """Load Telegram configuration from environment.

    Returns
    -------
    dict
        Configuration with 'token' and 'chat_id' keys.
        Values may be None if not configured.

    Notes
    -----
    Configuration sources (in priority order):
    1. Environment variables
       (OPENDEVIATIONBAR_TELEGRAM_TOKEN,
       OPENDEVIATIONBAR_TELEGRAM_CHAT_ID)
    2. Default chat ID (for internal use)
    """
    return {
        "token": os.environ.get("OPENDEVIATIONBAR_TELEGRAM_TOKEN"),
        "chat_id": os.environ.get(
            "OPENDEVIATIONBAR_TELEGRAM_CHAT_ID", _DEFAULT_CHAT_ID
        ),
    }


def is_configured() -> bool:
    """Check if Telegram notifications are configured.

    Returns
    -------
    bool
        True if both token and chat_id are available.
    """
    config = get_telegram_config()
    return bool(config.get("token") and config.get("chat_id"))


def send_telegram(
    message: str,
    *,
    parse_mode: str = "HTML",
    disable_notification: bool = False,
) -> int | bool:
    """Send a message via Telegram bot.

    Parameters
    ----------
    message : str
        Message text (supports HTML formatting).
    parse_mode : str
        Telegram parse mode ("HTML" or "Markdown").
    disable_notification : bool
        If True, send silently without notification sound.

    Returns
    -------
    int | bool
        Message ID (int) on success for use with delete_telegram_message(),
        False on failure.

    Examples
    --------
    >>> send_telegram("<b>Alert:</b> Cache write failed for BTCUSDT")
    12345
    """
    config = get_telegram_config()
    token = config.get("token")
    chat_id = config.get("chat_id")

    if not token:
        logger.warning(
            "Telegram not configured: OPENDEVIATIONBAR_TELEGRAM_TOKEN not set"
        )
        return False

    if not chat_id:
        logger.warning(
            "Telegram not configured: OPENDEVIATIONBAR_TELEGRAM_CHAT_ID not set"
        )
        return False

    # Import requests only when needed (optional dependency)
    try:
        import requests
    except ImportError:
        logger.warning("Telegram notifications require 'requests' package")
        return False

    url = f"https://api.telegram.org/bot{token}/sendMessage"
    payload = {
        "chat_id": chat_id,
        "text": message,
        "parse_mode": parse_mode,
        "disable_notification": disable_notification,
    }

    try:
        from opendeviationbar.config.network import NetworkConfig
        response = requests.post(url, json=payload, timeout=NetworkConfig().notification_timeout_s)
        response.raise_for_status()
        data = response.json()
        message_id = data.get("result", {}).get("message_id", 0)
        logger.debug("Telegram message sent successfully (id=%d)", message_id)
        return message_id if message_id else True
    except requests.exceptions.Timeout:
        logger.warning("Telegram notification timed out")
        return False
    except requests.exceptions.RequestException as e:
        logger.warning("Telegram notification failed: %s", e)
        return False


def delete_telegram_message(message_id: int) -> bool:
    """Delete a previously sent Telegram message.

    Parameters
    ----------
    message_id : int
        The message ID returned by send_telegram().

    Returns
    -------
    bool
        True if deleted successfully, False otherwise.
    """
    config = get_telegram_config()
    token = config.get("token")
    chat_id = config.get("chat_id")

    if not token or not chat_id:
        return False

    try:
        import requests
    except ImportError:
        return False

    url = f"https://api.telegram.org/bot{token}/deleteMessage"
    payload = {"chat_id": chat_id, "message_id": message_id}

    try:
        from opendeviationbar.config.network import NetworkConfig
        response = requests.post(url, json=payload, timeout=NetworkConfig().notification_timeout_s)
        response.raise_for_status()
        logger.debug("Telegram message %d deleted", message_id)
        return True
    except requests.exceptions.RequestException as e:
        logger.debug("Failed to delete Telegram message %d: %s", message_id, e)
        return False


def telegram_notify(payload: HookPayload) -> None:
    """Hook callback that sends notifications to Telegram.

    This function is designed to be registered as a hook callback.
    It formats the payload into a human-readable message and sends
    it to Telegram.

    Parameters
    ----------
    payload : HookPayload
        Event payload from the hooks system.

    Examples
    --------
    >>> from opendeviationbar.hooks import register_hook, HookEvent
    >>> register_hook(HookEvent.CACHE_WRITE_FAILED, telegram_notify)
    """
    emoji = "\u274c" if payload.is_failure else "\u2705"  # ❌ or ✅
    status = "FAILED" if payload.is_failure else "SUCCESS"

    # Format details as readable text
    details_text = ""
    if payload.details:
        details_lines = []
        for key, value in payload.details.items():
            # Handle nested dicts/lists
            if isinstance(value, dict | list):
                display_value = json.dumps(value, indent=2)
            else:
                display_value = value
            details_lines.append(f"  {key}: {display_value}")
        details_text = "\n".join(details_lines)

    message = f"""{emoji} <b>opendeviationbar-py {status}</b>

<b>Event:</b> {payload.event.value}
<b>Symbol:</b> {payload.symbol}
<b>Time:</b> {payload.timestamp.strftime("%Y-%m-%d %H:%M:%S UTC")}"""

    if details_text:
        message += f"""

<b>Details:</b>
<pre>{details_text}</pre>"""

    message += _build_context_block("hook")

    # Send silently for success, loudly for failures
    send_telegram(
        message,
        disable_notification=not payload.is_failure,
    )


def enable_telegram_notifications() -> bool:
    """Enable Telegram notifications for all hook events.

    Registers telegram_notify as a callback for all HookEvent types.

    Returns
    -------
    bool
        True if Telegram is configured and hooks were registered,
        False if Telegram is not configured.

    Examples
    --------
    >>> if enable_telegram_notifications():
    ...     print("Telegram notifications enabled")
    ... else:
    ...     print("Telegram not configured - set OPENDEVIATIONBAR_TELEGRAM_TOKEN")
    """
    if not is_configured():
        logger.warning(
            "Telegram not configured. "
            "Set OPENDEVIATIONBAR_TELEGRAM_TOKEN "
            "environment variable."
        )
        return False

    from ..hooks import HookEvent, register_hook

    for event in HookEvent:
        register_hook(event, telegram_notify)

    logger.info("Telegram notifications enabled for all hook events")
    return True


def enable_failure_notifications() -> bool:
    """Enable Telegram notifications for failure events only.

    Registers telegram_notify as a callback for all *_FAILED events.
    This is useful when you only want to be alerted about problems.

    Returns
    -------
    bool
        True if Telegram is configured and hooks were registered,
        False if Telegram is not configured.

    Examples
    --------
    >>> enable_failure_notifications()
    True
    """
    if not is_configured():
        logger.warning(
            "Telegram not configured. "
            "Set OPENDEVIATIONBAR_TELEGRAM_TOKEN "
            "environment variable."
        )
        return False

    from ..hooks import register_for_failures

    register_for_failures(telegram_notify)

    logger.info("Telegram notifications enabled for failure events")
    return True


__all__ = [
    "_build_context_block",
    "delete_telegram_message",
    "enable_failure_notifications",
    "enable_telegram_notifications",
    "get_telegram_config",
    "is_configured",
    "send_telegram",
    "set_start_time",
    "telegram_notify",
]
