"""
Signal Producer Service - Phase 17 P0 Router 層違規修復
======================================================

封裝 Redis Stream 的 Signal 生產邏輯，消除 Router 層直接存取 Redis。

功能:
- XADD 寫入 Redis Stream
- Trace Context 傳遞

符合 leWOOOgo 積木化規範:
- Router -> Service -> Redis
"""

import json
from dataclasses import dataclass
from typing import Any

import structlog

from src.core.redis_client import get_redis
from src.core.telemetry import get_trace_context
from src.utils.timezone import now_taipei

logger = structlog.get_logger(__name__)

# Redis Stream 配置
SIGNAL_STREAM_KEY = "awoooi:signals"
SIGNAL_STREAM_MAXLEN = 10000


@dataclass
class SignalData:
    """Signal 資料結構"""
    source: str
    alert_name: str
    severity: str
    namespace: str
    target: str
    message: str
    labels: dict[str, Any] | None = None
    annotations: dict[str, Any] | None = None


class SignalProducerService:
    """
    Signal 生產者服務

    封裝 Redis Stream 的 XADD 操作
    """

    async def produce(self, signal: SignalData) -> str:
        """
        將 Signal 寫入 Redis Stream

        Phase 17: 從 Router 層遷移至 Service 層

        使用 Redis Streams (XADD) 實現非同步事件總線:
        - MAXLEN ~10000: 限制 Stream 長度，自動裁剪舊訊息
        - *: 自動生成 Message ID

        Args:
            signal: Signal 資料

        Returns:
            str: Redis Stream Message ID
        """
        redis_client = get_redis()

        # 組裝 Signal 字典 (所有值必須是字串)
        signal_dict = {
            "source": signal.source,
            "alert_name": signal.alert_name,
            "severity": signal.severity,
            "namespace": signal.namespace,
            "target": signal.target,
            "message": signal.message,
            "labels": json.dumps(signal.labels or {}),
            "annotations": json.dumps(signal.annotations or {}),
            "received_at": now_taipei().isoformat(),
        }

        # Phase 15.2: 注入 Trace Context
        trace_ctx = get_trace_context()
        if trace_ctx:
            signal_dict["_trace_id"] = trace_ctx.get("trace_id", "")
            signal_dict["_span_id"] = trace_ctx.get("span_id", "")

        # XADD 寫入 Stream
        message_id = await redis_client.xadd(
            SIGNAL_STREAM_KEY,
            signal_dict,
            maxlen=SIGNAL_STREAM_MAXLEN,
            approximate=True,  # ~MAXLEN 近似裁剪，效能更好
        )

        logger.info(
            "signal_produced",
            message_id=message_id,
            source=signal.source,
            alert_name=signal.alert_name,
            severity=signal.severity,
            trace_id=trace_ctx.get("trace_id") if trace_ctx else None,
        )

        return message_id


# =============================================================================
# Singleton
# =============================================================================

_signal_producer: SignalProducerService | None = None


def get_signal_producer() -> SignalProducerService:
    """取得 SignalProducerService 實例 (Singleton)"""
    global _signal_producer
    if _signal_producer is None:
        _signal_producer = SignalProducerService()
    return _signal_producer
