#!/usr/bin/env python3
"""
企微智能机器人 — WebSocket 长连接客户端
协议: wss://openws.work.weixin.qq.com

用法:
  1. 替换 BOT_ID 和 BOT_SECRET
  2. pip install websocket-client
  3. python aibot_ws_client.py
"""

import json
import time
import uuid
import logging
import sys
import os

import websocket

# ── 配置 ──────────────────────────────────────────────
BOT_ID = "YOUR_BOT_ID"
BOT_SECRET = "YOUR_SECRET"
WS_URL = "wss://openws.work.weixin.qq.com"

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s [%(levelname)s] %(message)s",
    handlers=[
        logging.StreamHandler(sys.stderr),
        logging.FileHandler(os.path.join(os.path.dirname(__file__), "aibot_ws.log")),
    ],
)
log = logging.getLogger("aibot")

# ── 消息处理器 ────────────────────────────────────────
def on_msg_callback(body: dict, ws_app):
    """收到用户消息"""
    msgtype = body.get("msgtype", "")
    chatid = body.get("chatid", "")
    from_user = body.get("from", {}).get("userid", "")
    msgid = body.get("msgid", "")

    if msgtype == "text":
        content = body.get("text", {}).get("content", "")
        log.info(f"📩 消息 | chat={chatid} user={from_user}: {content[:80]}")

        # TODO: 接入实际业务逻辑
        reply_text = f"收到: {content[:100]}"
        send_reply(ws_app, msgid, reply_text)

    elif msgtype == "event":
        event_type = body.get("event", {}).get("eventtype", "")
        log.info(f"📩 事件 | chat={chatid}: {event_type}")

    else:
        log.info(f"📩 其他类型: {msgtype}")


def on_event_callback(body: dict, ws_app):
    event = body.get("event", {})
    event_type = event.get("eventtype", "")
    from_user = body.get("from", {}).get("userid", "")

    if event_type == "enter_chat":
        log.info(f"👋 用户进入 | user={from_user}")
        send_welcome(ws_app)

    elif event_type == "disconnected_event":
        log.warning("⚠️ 连接断开事件")


# ── 发送消息 ──────────────────────────────────────────
def _send(ws_app, cmd: str, body: dict):
    msg = {
        "cmd": cmd,
        "headers": {"req_id": str(uuid.uuid4())},
        "body": body,
    }
    ws_app.send(json.dumps(msg, ensure_ascii=False))


def send_reply(ws_app, msgid: str, text: str, finish: bool = True):
    _send(ws_app, "aibot_respond_msg", {
        "msgtype": "stream",
        "stream": {"id": msgid, "finish": finish, "content": text},
    })


def send_welcome(ws_app):
    _send(ws_app, "aibot_respond_welcome_msg", {
        "msgtype": "text",
        "text": {"content": "你好！有什么可以帮你的？"},
    })


def send_markdown(ws_app, chatid: str, content: str):
    _send(ws_app, "aibot_send_msg", {
        "chatid": chatid,
        "chat_type": 1,
        "msgtype": "markdown",
        "markdown": {"content": content},
    })


# ── WebSocket 回调 ────────────────────────────────────
def on_open(ws_app):
    log.info("🔌 WebSocket 已连接")
    _send(ws_app, "aibot_subscribe", {
        "bot_id": BOT_ID, "secret": BOT_SECRET,
    })


def on_message(ws_app, raw: str):
    log.debug(f"📩 RAW: {raw[:300]}")
    try:
        msg = json.loads(raw)
    except json.JSONDecodeError:
        log.warning(f"非法 JSON: {raw[:200]}")
        return

    cmd = msg.get("cmd", "")
    body = msg.get("body", {})
    errcode = msg.get("errcode")

    # 订阅确认
    if errcode is not None and not cmd:
        if errcode == 0:
            log.info("✅ 订阅成功")
        else:
            log.error(f"❌ 订阅失败: {msg.get('errmsg')}")
        return

    if cmd == "aibot_msg_callback":
        on_msg_callback(body, ws_app)
    elif cmd == "aibot_event_callback":
        on_event_callback(body, ws_app)


def on_error(ws_app, error):
    log.error(f"❌ WebSocket 错误: {error}")


def on_close(ws_app, code, msg):
    log.warning(f"🔌 关闭 | code={code}")


def run_forever():
    while True:
        try:
            ws_app = websocket.WebSocketApp(
                WS_URL,
                on_open=on_open,
                on_message=on_message,
                on_error=on_error,
                on_close=on_close,
            )
            ws_app.run_forever(ping_interval=30, ping_timeout=10)
        except Exception as e:
            log.error(f"异常: {e}")
        time.sleep(5)


if __name__ == "__main__":
    run_forever()
