# AI_CHANGELOG
# - 2026-02-19 | Prompt: 配置微信消息推送 | 新增微信消息推送回调接口，支持 GET 验签 + POST 消息接收

"""
微信消息推送回调接口

处理两类请求：
1. GET  — 微信服务器验证（配置时触发一次）
2. POST — 接收微信推送的消息/事件

安全模式下需要解密消息体，当前先用明文模式跑通，后续切安全模式。
"""

import hashlib
import logging

from fastapi import APIRouter, Query, Request, Response

from app.config import get

logger = logging.getLogger(__name__)

router = APIRouter(prefix="/api/wx", tags=["微信回调"])

# Token 从环境变量读取，与微信后台填写的一致
# 放在 apps/backend/.env.local 中：WX_CALLBACK_TOKEN=你自定义的token
WX_CALLBACK_TOKEN: str = get("WX_CALLBACK_TOKEN", "")


def _check_signature(signature: str, timestamp: str, nonce: str) -> bool:
    """
    验证请求是否来自微信服务器。

    将 Token、timestamp、nonce 字典序排序后拼接，做 SHA1，
    与 signature 比对。
    """
    if not WX_CALLBACK_TOKEN:
        logger.error("WX_CALLBACK_TOKEN 未配置")
        return False

    items = sorted([WX_CALLBACK_TOKEN, timestamp, nonce])
    hash_str = hashlib.sha1("".join(items).encode("utf-8")).hexdigest()
    return hash_str == signature


@router.get("/callback")
async def verify(
    signature: str = Query(...),
    timestamp: str = Query(...),
    nonce: str = Query(...),
    echostr: str = Query(...),
):
    """
    微信服务器验证接口。

    配置消息推送时微信会发 GET 请求，验签通过后原样返回 echostr。
    """
    if _check_signature(signature, timestamp, nonce):
        logger.info("微信回调验证通过")
        # 必须原样返回 echostr（纯文本，不能包裹 JSON）
        return Response(content=echostr, media_type="text/plain")
    else:
        logger.warning("微信回调验签失败: signature=%s", signature)
        return Response(content="signature mismatch", status_code=403)


@router.post("/callback")
async def receive_message(
    request: Request,
    signature: str = Query(""),
    timestamp: str = Query(""),
    nonce: str = Query(""),
):
    """
    接收微信推送的消息/事件。

    当前为明文模式，直接解析 JSON 包体。
    后续切安全模式时需增加 AES 解密逻辑。
    """
    # 验签（POST 也带 signature 参数）
    if not _check_signature(signature, timestamp, nonce):
        logger.warning("消息推送验签失败")
        return Response(content="signature mismatch", status_code=403)

    # 解析消息体
    body = await request.body()
    content_type = request.headers.get("content-type", "")

    if "json" in content_type:
        import json
        try:
            data = json.loads(body)
        except json.JSONDecodeError:
            data = {"raw": body.decode("utf-8", errors="replace")}
    else:
        # XML 格式暂不解析，记录原文
        data = {"raw_xml": body.decode("utf-8", errors="replace")}

    logger.info("收到微信推送: MsgType=%s, Event=%s",
                data.get("MsgType", "?"), data.get("Event", "?"))

    # TODO: 根据 MsgType/Event 分发处理（客服消息、订阅事件等）
    # 当前统一返回 success
    return Response(content="success", media_type="text/plain")
