# -*- coding: utf-8 -*-
"""
Telegram 频道监听器（Telethon MTProto）
- 订阅多个公开频道，实时捕获消息
- 消息推入 CHANNEL_NEWS_QUEUE（线程安全），供 analyzer 消费
- 在独立线程中运行独立 asyncio 事件循环
"""

import asyncio
import logging
import queue
import threading
import time

from telethon import TelegramClient, events
from telethon.errors import FloodWaitError

logger = logging.getLogger("MyTrader")

# 全局共享队列，analyzer 直接读取
CHANNEL_NEWS_QUEUE: queue.Queue = queue.Queue(maxsize=500)

import os as _os
_SESSION_STRING = _os.getenv("TG_SESSION_STRING", "")
_listener_thread = None
_loop = None


def start_channel_listener(api_id: int, api_hash: str, channels: list, proxies: dict = None):
    """在后台线程启动 Telethon 频道监听，幂等（重复调用无副作用）。"""
    global _listener_thread
    if _listener_thread and _listener_thread.is_alive():
        return

    def _run():
        global _loop
        _loop = asyncio.new_event_loop()
        asyncio.set_event_loop(_loop)
        try:
            _loop.run_until_complete(_listen(api_id, api_hash, channels, proxies))
        except Exception as e:
            logger.error(f"[TGChannel] 监听线程异常退出: {e}")

    _listener_thread = threading.Thread(target=_run, name="TGChannelListener", daemon=True)
    _listener_thread.start()
    logger.info(f"[TGChannel] 监听线程已启动，订阅: {channels}")


async def _listen(api_id: int, api_hash: str, channels: list, proxies: dict):
    proxy = None
    if proxies:
        import re
        m = re.match(r'https?://([^:]+):(\d+)', proxies.get("http", ""))
        if m:
            import socks
            proxy = (socks.HTTP, m.group(1), int(m.group(2)))

    from telethon.sessions import StringSession
    client = TelegramClient(StringSession(_SESSION_STRING), api_id, api_hash, proxy=proxy)
    await client.connect()
    if not await client.is_user_authorized():
        logger.error("[TGChannel] Session无效")
        return
    logger.info("[TGChannel] Telethon 已登录")

    # 解析频道实体
    resolved = []
    for ch in channels:
        try:
            entity = await client.get_entity(ch)
            resolved.append(entity)
            logger.info(f"[TGChannel] 已订阅: {ch} → {getattr(entity, 'title', ch)}")
        except Exception as e:
            logger.warning(f"[TGChannel] 无法解析频道 {ch}: {e}")

    if not resolved:
        logger.error("[TGChannel] 没有任何频道可订阅，退出监听")
        return

    @client.on(events.NewMessage(chats=resolved))
    async def _handler(event):
        try:
            msg = event.message
            text = (msg.text or msg.message or "").strip()
            if not text or len(text) < 5:
                return
            chat = await event.get_chat()
            source = getattr(chat, "title", getattr(chat, "username", "unknown"))
            item = {
                "id": msg.id,
                "ts": msg.date.timestamp() if msg.date else time.time(),
                "source": source,
                "text": text[:600],
            }
            try:
                CHANNEL_NEWS_QUEUE.put_nowait(item)
            except queue.Full:
                # 队列满时丢弃最旧一条
                try:
                    CHANNEL_NEWS_QUEUE.get_nowait()
                    CHANNEL_NEWS_QUEUE.put_nowait(item)
                except Exception:
                    pass
        except Exception as e:
            logger.debug(f"[TGChannel] 消息处理异常: {e}")

    logger.info(f"[TGChannel] 开始监听 {len(resolved)} 个频道...")
    try:
        await client.run_until_disconnected()
    except FloodWaitError as e:
        logger.warning(f"[TGChannel] FloodWait，等待 {e.seconds}s")
        await asyncio.sleep(e.seconds)
    except Exception as e:
        logger.error(f"[TGChannel] 连接断开: {e}，30s 后重连")
        await asyncio.sleep(30)


def drain_channel_news(max_age_s: float = 300) -> list:
    """
    取出队列中所有消息，过滤超过 max_age_s 秒的旧消息。
    返回列表: [{"source": str, "text": str, "ts": float, "age_s": int}, ...]
    """
    now = time.time()
    items = []
    while True:
        try:
            item = CHANNEL_NEWS_QUEUE.get_nowait()
        except queue.Empty:
            break
        age_s = now - item.get("ts", now)
        if age_s <= max_age_s:
            items.append({
                "source": item["source"],
                "text": item["text"],
                "ts": item["ts"],
                "age_s": int(age_s),
            })
    return items
