"""HTTP chat proxy helpers for opt-in Telegram agent routing."""

from __future__ import annotations

import re
from html import escape
from typing import Any

DEFAULT_SMART_RESEARCH_COMMAND_PREFIXES = ("/smart_research", "/paid_research")
SMART_RESEARCH_PAYMENT_ACK_TEXT = "Payment received. Research is starting now."
_TELEGRAM_COMMAND_NAME_RE = re.compile(r"^[A-Za-z0-9_]+$")
_SMART_RESEARCH_PAYMENT_ACK_PREFIX_RE = re.compile(
    r"^\s*"
    r"Payment received[.!]\s*"
    r"(?:Research is starting now[.!]\s*)?"
    r"(?:I will use the included source-tool budget and continue with the answer here[.!]\s*)?",
    re.IGNORECASE,
)
_AUTO_SMART_RESEARCH_RE = re.compile(
    r"\b("
    r"research|source|sources|citation|citations|evidence|"
    r"search|find|lookup|look\s+up|web|"
    r"latest|current|today|recent|as\s+of|this\s+week|this\s+month|"
    r"twitter|x\.com|tweet|tweets|social|social\s+media|trend|trends|"
    r"discussion|discussions|sentiment|narrative|narratives|"
    r"revenue|revenues|fees|tvl|volume|fdv|fully\s+diluted|"
    r"market\s+cap|mcap|valuation|funding|liquidity|price|chart|"
    r"token|coin|pair|pool|dex|dexscreener|birdeye|jupiter|"
    r"buy|sell|should\s+i|yes\s+or\s+no|"
    r"estimate|compare|benchmark"
    r")\b",
    re.IGNORECASE,
)
_AUTO_CONTEXTUAL_RESEARCH_RE = re.compile(
    r"("
    r"\b(what\s+are\s+your\s+thoughts|thoughts\s+on|take\s+on|opinion\s+on|"
    r"how\s+did|how\s+has|how\s+is|assess|evaluate)\b"
    r".*\b(managed|manage|handled|handle|handling|responded|response|situation|incident|"
    r"controversy|fallout|fault|blame|position|stance|fair|valuation|valued|growth|metrics|peers?)\b"
    r"|"
    r"\b(who|what|why)\s+(was\s+)?(at\s+)?fault\b"
    r"|"
    r"\b(position|stance)\s+(on|about|towards?)\b"
    r"|"
    r"\b(compare|benchmark)\b.*\b(metrics|growth|valuation|peers?|fintech|web2|products?)\b"
    r")",
    re.IGNORECASE,
)
_AUTO_SMART_RESEARCH_FOLLOWUP_RE = re.compile(
    r"\b("
    r"check\s+it\s+yourself|check\s+yourself|actually\s+check|"
    r"look\s+it\s+up|look\s+that\s+up|search\s+it|search\s+that|"
    r"use\s+(the\s+)?web|use\s+sources|find\s+sources|"
    r"do\s+the\s+research|go\s+research|verify\s+it"
    r")\b",
    re.IGNORECASE,
)
_PAID_WORK_ORDER_ID_RE = re.compile(
    r"\b((?:sponsored_work_orders|payment_receipts):[a-f0-9]{16,64})\b",
    re.IGNORECASE,
)
_MARKET_CONTEXT_RE = re.compile(
    r"\b("
    r"volume|fdv|fully\s+diluted|market\s+cap|mcap|liquidity|price|chart|"
    r"token|coin|pair|pool|dex|dexscreener|birdeye|jupiter|"
    r"buy|sell|should\s+i|yes\s+or\s+no"
    r")\b",
    re.IGNORECASE,
)
_SOCIAL_DISCUSSION_RE = re.compile(
    r"\b(twitter|x\.com|x\/twitter|tweet|tweets|social)\b.*"
    r"\b(current|latest|recent|discussion|discussions|trend|trends|narrative|sentiment|fault|blame|position|stance)\b"
    r"|"
    r"\b(current|latest|recent|discussion|discussions|trend|trends|narrative|sentiment|fault|blame|position|stance)\b.*"
    r"\b(twitter|x\.com|x\/twitter|tweet|tweets|social)\b",
    re.IGNORECASE,
)


def _normalize_chat_title(value: str | None) -> str:
    return re.sub(r"\s+", " ", str(value or "")).strip().casefold()


def smart_research_chat_matches_gate(
    *,
    chat_id: int,
    chat_title: str | None = None,
    allowed_chat_id: str | None = None,
    allowed_chat_title: str | None = None,
) -> bool:
    """Return whether a Telegram chat matches the configured paid-research gate."""
    if allowed_chat_id and allowed_chat_id.strip() == str(chat_id):
        return True

    if not allowed_chat_title:
        return False

    normalized_title = _normalize_chat_title(chat_title)
    if not normalized_title:
        return False

    allowed_titles = {
        _normalize_chat_title(part)
        for part in re.split(r"[,;\n]", allowed_chat_title)
        if _normalize_chat_title(part)
    }
    return normalized_title in allowed_titles


def smart_research_command_names(
    command_prefixes: tuple[str, ...] | list[str] = DEFAULT_SMART_RESEARCH_COMMAND_PREFIXES,
) -> list[str]:
    """Return Telegram command names registered for smart-research routing."""
    command_names: set[str] = set()
    for prefix in command_prefixes:
        command = str(prefix).strip()
        if not command.startswith("/"):
            continue
        command = command[1:].split("@", 1)[0].strip()
        if command and _TELEGRAM_COMMAND_NAME_RE.match(command):
            command_names.add(command)
    return sorted(command_names)


def build_chat_proxy_payload(
    *,
    message: str,
    source: str,
    agent: str,
    chat_id: int | None = None,
    message_id: int | None = None,
    username: str | None = None,
) -> dict[str, Any]:
    """Build the no-secret payload sent from Telegram to an agent HTTP chat route."""
    metadata = {
        "source": source,
        "agent": agent,
        "chat_id": chat_id,
        "message_id": message_id,
        "username": username,
    }
    return {
        "message": message,
        "metadata": {k: v for k, v in metadata.items() if v is not None},
    }


def extract_smart_research_goal(
    message: str,
    command_prefixes: tuple[str, ...] | list[str] = DEFAULT_SMART_RESEARCH_COMMAND_PREFIXES,
) -> str | None:
    """Return the research goal when a Telegram message opts into smart research."""
    text = message.strip()
    for prefix in command_prefixes:
        command = re.escape(prefix.lstrip("/"))
        match = re.match(rf"^(?:@\w+\s+)?/{command}(?:@\w+)?(?:\s+(?P<goal>.+))?$", text, re.IGNORECASE)
        if match:
            goal = (match.group("goal") or "").strip()
            return goal or None
    return None


def extract_auto_smart_research_goal(
    message: str,
    mention_aliases: tuple[str, ...] | list[str] = (),
) -> str | None:
    """Return a research goal when ordinary chat clearly asks for sourced/current research."""
    text = message.strip()
    for alias in mention_aliases:
        clean_alias = str(alias).strip()
        if not clean_alias:
            continue
        text = re.sub(rf"(^|\s){re.escape(clean_alias)}(?:@\w+)?\b", " ", text, flags=re.IGNORECASE).strip()
    text = re.sub(r"\s+", " ", text).strip()
    if not text or text.startswith("/"):
        return None
    if _AUTO_SMART_RESEARCH_RE.search(text) or _AUTO_CONTEXTUAL_RESEARCH_RE.search(text):
        return text
    return None


def extract_auto_smart_research_followup_goal(
    message: str,
    previous_user_message: str | None,
    mention_aliases: tuple[str, ...] | list[str] = (),
) -> str | None:
    """Turn short follow-ups like 'check it yourself' into the prior research goal."""
    text = message.strip()
    for alias in mention_aliases:
        clean_alias = str(alias).strip()
        if not clean_alias:
            continue
        text = re.sub(rf"(^|\s){re.escape(clean_alias)}(?:@\w+)?\b", " ", text, flags=re.IGNORECASE).strip()
    text = re.sub(r"\s+", " ", text).strip()
    if not text or text.startswith("/") or not _AUTO_SMART_RESEARCH_FOLLOWUP_RE.search(text):
        return None
    previous_goal = extract_auto_smart_research_goal(previous_user_message or "", mention_aliases)
    if not previous_goal:
        return None
    return (
        f"{previous_goal}\n\n"
        f"Follow-up instruction: {text}. Use current public sources and cite assumptions. "
        "For buy/sell wording, do not provide personalized financial advice; provide market data, risks, "
        "and a concise non-advice thesis."
    )


def extract_paid_work_order_id(message: str) -> str | None:
    """Return a paid x402 work-order/receipt id from ordinary Telegram text."""
    match = _PAID_WORK_ORDER_ID_RE.search(message.strip())
    if not match:
        return None
    return match.group(1)


def extract_checkout_qr_url(payload: dict[str, Any] | None) -> str | None:
    """Return a Telegram-safe checkout QR image URL from a Leo research response."""
    if not isinstance(payload, dict):
        return None
    checkout = payload.get("checkout")
    if not isinstance(checkout, dict):
        return None
    raw_url = checkout.get("checkoutQrUrl") or checkout.get("checkout_qr_url")
    if not isinstance(raw_url, str):
        return None
    url = raw_url.strip()
    if len(url) > 2000:
        return None
    if not re.match(r"^https://leo\.livingip\.xyz/api/agents/leo/research/checkout-qr\?", url):
        return None
    return url


def extract_checkout_url(payload: dict[str, Any] | None) -> str | None:
    """Return an explicitly provided Telegram-safe Leo checkout URL for a payment button."""
    if not isinstance(payload, dict):
        return None
    checkout = payload.get("checkout")
    if not isinstance(checkout, dict):
        return None
    telegram = checkout.get("telegram")
    raw_url = None
    if isinstance(telegram, dict):
        raw_url = telegram.get("buttonUrl") or telegram.get("button_url")
    if not isinstance(raw_url, str):
        return None
    url = raw_url.strip()
    if len(url) > 2000:
        return None
    if not re.match(r"^https://leo\.livingip\.xyz/agents/leo/research/checkout\?", url):
        return None
    return url


def extract_checkout_qr_photo_message(payload: dict[str, Any] | None) -> dict[str, str] | None:
    """Return a compact Telegram photo+caption payload for a Leo paid-research quote."""
    qr_url = extract_checkout_qr_url(payload)
    if not qr_url or not isinstance(payload, dict):
        return None

    checkout = payload.get("checkout")
    if not isinstance(checkout, dict):
        return None

    telegram = checkout.get("telegram")
    caption_html = None
    button_text = "Pay with x402"
    if isinstance(telegram, dict):
        raw_caption = telegram.get("captionHtml") or telegram.get("caption_html")
        if isinstance(raw_caption, str) and 1 <= len(raw_caption) <= 1024:
            caption_html = raw_caption.strip()
        raw_button_text = telegram.get("buttonText") or telegram.get("button_text")
        if isinstance(raw_button_text, str) and 1 <= len(raw_button_text.strip()) <= 40:
            button_text = raw_button_text.strip()

    if not caption_html:
        price = str(checkout.get("priceUsd") or checkout.get("price_usd") or "0.07").strip()
        network = str(checkout.get("networkLabel") or checkout.get("network") or "Solana mainnet").strip()
        payment_address = checkout.get("paymentAddress") or checkout.get("payment_address")
        address_line = (
            f"Recipient: <code>{escape(str(payment_address), quote=False)}</code>"
            if isinstance(payment_address, str) and payment_address.strip()
            else None
        )
        caption_html = "\n".join(
            line
            for line in [
                "<b>Paid Leo research</b>",
                f"{escape(price, quote=False)} USDC on {escape(network, quote=False)}.",
                "Scan the QR to pay. I will continue here after payment.",
                address_line,
            ]
            if line
        )

    if len(caption_html) > 1024:
        caption_html = caption_html[:1000].rstrip() + "..."

    return {
        "photo_url": qr_url,
        "caption_html": caption_html,
        "parse_mode": "HTML",
        "button_text": button_text,
        "button_url": extract_checkout_url(payload) or "",
    }


def should_attach_structured_market_context(message: str) -> bool:
    """Return true only for explicit market-data questions, not social narrative research."""
    text = message.strip()
    if not text:
        return False
    if _SOCIAL_DISCUSSION_RE.search(text):
        return False
    return bool(_MARKET_CONTEXT_RE.search(text))


def smart_research_payment_fields_for_message(
    *,
    paid_work_order_id: str | None,
    configured_payment_gate: dict[str, Any],
) -> dict[str, Any]:
    """Return paid-execution fields only for a settled work-order resume message."""
    if not paid_work_order_id:
        return {"allow_paid_execution": False}
    if configured_payment_gate.get("allow_paid_execution") is True:
        return configured_payment_gate
    return {"allow_paid_execution": False}


def classify_smart_research_auto_resume_response(
    http_status: int,
    payload: dict[str, Any] | None,
) -> str:
    """Classify a poll response for Telegram auto-resume.

    Returns:
    - pending: the payment/work order is not visible yet; keep polling silently.
    - ready: the route has a final user-facing reply or a visible paid-work-order blocker.
    - ignore: the response is unrelated to an auto-resume poll.
    """
    if not isinstance(payload, dict):
        return "ignore"
    status = str(payload.get("status") or "").strip()
    auto_resume = payload.get("autoResume")
    paid_work_order = payload.get("paidWorkOrder")
    auto_activated = isinstance(auto_resume, dict) and auto_resume.get("activated") is True
    work_order_settled = (
        isinstance(paid_work_order, dict) and paid_work_order.get("status") == "settled"
    )
    if status == "payment_authorization_required" and not auto_activated and not work_order_settled:
        return "pending"
    if auto_activated or work_order_settled:
        return "ready"
    if http_status < 400 and status and status != "payment_authorization_required":
        return "ready"
    return "ignore"


def split_smart_research_auto_resume_reply(
    payload: dict[str, Any] | None,
    reply: str | None,
) -> tuple[str | None, str | None]:
    """Split a paid auto-resume reply into receipt ack and answer text.

    The HTTP route may return one combined reply starting with "Payment
    received...". Telegram should show that as two messages: a quick payment
    receipt first, then the research result or clean tool-failure message.
    """
    if not isinstance(reply, str) or not reply.strip():
        return None, None
    text = reply.strip()
    if not isinstance(payload, dict):
        return None, text

    auto_resume = payload.get("autoResume")
    paid_work_order = payload.get("paidWorkOrder")
    paid_resume = (
        isinstance(auto_resume, dict)
        and auto_resume.get("activated") is True
        or isinstance(paid_work_order, dict)
        and paid_work_order.get("status") == "settled"
    )
    if not paid_resume:
        return None, text

    answer = _SMART_RESEARCH_PAYMENT_ACK_PREFIX_RE.sub("", text, count=1).strip()
    return SMART_RESEARCH_PAYMENT_ACK_TEXT, answer or None


def build_smart_research_proxy_payload(
    *,
    research_goal: str,
    source: str,
    agent: str,
    chat_id: int | None = None,
    message_id: int | None = None,
    username: str | None = None,
    allow_paid_execution: bool = False,
    approval_ref: str | None = None,
    max_amount_usd: float | None = None,
    include_synthesis: bool = True,
    work_order_id: str | None = None,
    original_research_goal: str | None = None,
    auto_resume_poll: bool = False,
) -> dict[str, Any]:
    """Build the no-secret Telegram payload for Leo smart research."""
    payload = build_chat_proxy_payload(
        message=research_goal,
        source=source,
        agent=agent,
        chat_id=chat_id,
        message_id=message_id,
        username=username,
    )
    payload.update(
        {
            "research_goal": research_goal,
            "allow_paid_execution": bool(allow_paid_execution),
            "include_synthesis": bool(include_synthesis),
        }
    )
    if max_amount_usd is not None:
        payload["max_amount_usd"] = max_amount_usd
    if allow_paid_execution and approval_ref:
        payload["approval_ref"] = approval_ref
    if work_order_id:
        payload["work_order_id"] = work_order_id
    if original_research_goal:
        payload["original_research_goal"] = original_research_goal
    if auto_resume_poll:
        metadata = payload.setdefault("metadata", {})
        if isinstance(metadata, dict):
            metadata["auto_resume_poll"] = True
    return payload


def extract_chat_proxy_reply(payload: dict[str, Any]) -> str | None:
    """Extract only user-facing replies from supported Living IP Leo response shapes."""
    if not isinstance(payload, dict):
        return None

    direct_reply = payload.get("reply")
    if isinstance(direct_reply, str) and direct_reply.strip():
        return direct_reply.strip()

    decision = payload.get("decision")
    if isinstance(decision, dict):
        decision_reply = decision.get("reply")
        if isinstance(decision_reply, str) and decision_reply.strip():
            return decision_reply.strip()

    llm = payload.get("llm")
    if isinstance(llm, dict):
        llm_reply = llm.get("reply")
        if isinstance(llm_reply, str) and llm_reply.strip():
            return llm_reply.strip()
        llm_decision = llm.get("decision")
        if isinstance(llm_decision, dict):
            llm_decision_reply = llm_decision.get("reply")
            if isinstance(llm_decision_reply, str) and llm_decision_reply.strip():
                return llm_decision_reply.strip()

    synthesis = payload.get("synthesis")
    if isinstance(synthesis, dict):
        synthesis_reply = synthesis.get("reply")
        if isinstance(synthesis_reply, str) and synthesis_reply.strip():
            return synthesis_reply.strip()
        synthesis_decision = synthesis.get("decision")
        if isinstance(synthesis_decision, dict):
            synthesis_decision_reply = synthesis_decision.get("reply")
            if isinstance(synthesis_decision_reply, str) and synthesis_decision_reply.strip():
                return synthesis_decision_reply.strip()

    return None


async def post_chat_proxy(
    *,
    url: str,
    payload: dict[str, Any],
    timeout_seconds: int = 30,
) -> tuple[int, dict[str, Any], str | None]:
    """POST to an agent HTTP chat route and return status, JSON body, and reply."""
    import aiohttp

    async with aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=timeout_seconds)) as session:
        async with session.post(
            url,
            json=payload,
            headers={
                "Accept": "application/json",
                "Content-Type": "application/json",
                "X-LivingIP-Source": "telegram-agent-proxy",
            },
        ) as resp:
            data = await resp.json(content_type=None)
            return resp.status, data, extract_chat_proxy_reply(data)
