# apps/api/src/api/v1/aider_events.py | 2026-04-20 @ Asia/Taipei
"""POST /api/v1/aider/events — Mac aiderw client 推事件入口。
HMAC-SHA256 verified; 推入 Redis stream 讓 background job 處理。"""
from __future__ import annotations
import hmac
import hashlib
import os
import structlog
from fastapi import APIRouter, Header, HTTPException, Request, status
from pydantic import ValidationError
from src.models.aider import AiderBatchIn
from src.services.aider_event_service import push_aider_batch_to_stream

logger = structlog.get_logger(__name__)
router = APIRouter(prefix="/aider", tags=["Aider"])


def _verify_signature(body: bytes, signature: str | None, secret: str) -> bool:
    """Timing-safe HMAC-SHA256 比對。signature 格式 'sha256=<hex>'。"""
    if not signature or not signature.startswith("sha256=") or not secret:
        return False
    expected = "sha256=" + hmac.new(secret.encode(), body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, signature)


@router.post("/events", status_code=status.HTTP_202_ACCEPTED)
async def receive_aider_events(
    request: Request,
    x_aider_signature: str | None = Header(default=None, alias="X-Aider-Signature"),
):
    """接收 Mac aiderw 推來的 event batch，HMAC 驗證後推 Redis stream。"""
    body = await request.body()

    secret = os.environ.get("AIDER_WEBHOOK_SECRET", "")
    if not _verify_signature(body, x_aider_signature, secret):
        logger.warning("aider_webhook_signature_invalid")
        raise HTTPException(status_code=401, detail="invalid signature")

    try:
        batch = AiderBatchIn.model_validate_json(body)
    except ValidationError as e:
        # 只回前 5 筆錯誤避免巨大 response
        raise HTTPException(status_code=400, detail=e.errors()[:5])

    # 推 Redis stream（透過 Service 層）
    try:
        stream_ids = await push_aider_batch_to_stream(batch)
    except Exception as exc:
        logger.exception("aider_webhook_redis_push_failed")
        raise HTTPException(status_code=503, detail="queue unavailable") from exc

    logger.info("aider_webhook_accepted", count=len(batch.events))
    return {"accepted": len(batch.events), "stream_ids": stream_ids}
