# app/src/notifications/templates/signal.py

from __future__ import annotations

from src.core.numbers import safe_float
from src.core.types import JsonDict, JsonList, NumericLike
from src.notifications.models import NotificationMessage
from src.runtime_events.event_types import RuntimeEventType
from src.runtime_events.models import RuntimeEvent


def build_signal_notification(event: RuntimeEvent) -> NotificationMessage | None:
    if event.event_type != RuntimeEventType.AUTO_SIGNAL_READY:
        return None

    payload: JsonDict = event.payload

    signal = str(payload.get("signal") or "—").upper()
    symbol = _format_symbol(str(payload.get("symbol") or "—"))
    confidence = safe_float(payload.get("confidence")) or 0.0
    repeat_count = int(safe_float(payload.get("repeat_count")) or 0)

    position_context = str(payload.get("position_context") or "NONE").upper()
    semantic_lines = _as_json_list(payload.get("semantic_lines"))

    priority = str(
        event.priority
        or _alert_priority(
            confidence=confidence,
            repeat_count=repeat_count,
        )
    ).upper()

    direction = _signal_direction(signal)
    direction_key = direction.upper()
    icon = _direction_icon(direction)
    strength = _strength_label(priority)
    strength_bar = _strength_bar(priority)

    lines = [
        f"⚡️ Сигнал · <b>{symbol}</b> {icon} {direction}",
        f"{strength_bar} {strength} · {confidence:.2f}",
        f"Серия {signal} · ×{repeat_count}",
    ]

    if semantic_lines:
        lines.extend(
            str(line).strip().rstrip(".")
            for line in semantic_lines
            if str(line).strip()
        )

    price_lines = _market_price_lines(
        direction=direction_key,
        bid_price=payload.get("bid_price"),
        ask_price=payload.get("ask_price"),
    )

    if price_lines:
        lines.extend(price_lines)

    position_line = _position_context_line(
        signal=signal,
        position_context=position_context,
    )

    if position_line:
        lines.append(position_line)

    block_lines = _execution_block_lines(payload)
    if block_lines:
        lines.extend(["", *block_lines])

    return NotificationMessage(
        title=event.title,
        text="\n".join(lines),
        priority=priority.lower(),
        dedupe_key=event.dedupe_key or _dedupe_key(payload),
    )


def _execution_block_lines(payload: JsonDict) -> list[str]:
    title = str(payload.get("execution_block_title") or "").strip()
    message = str(payload.get("execution_block_message") or "").strip()
    action = str(payload.get("execution_block_action") or "").strip()

    if not title or not message:
        return []

    lines = [
        f"⛔ {title}",
        message,
    ]

    if action:
        lines.append(action)

    return lines


def _position_context_line(
    *,
    signal: str,
    position_context: str,
) -> str:
    if position_context in {"NONE", "—", ""}:
        return ""

    if position_context == "LONG" and signal == "BUY":
        return "ℹ️ В сторону открытой позиции"

    if position_context == "SHORT" and signal == "SELL":
        return "ℹ️ В сторону открытой позиции"

    if position_context == "LONG" and signal == "SELL":
        return "⚠️ Против открытой позиции"

    if position_context == "SHORT" and signal == "BUY":
        return "⚠️ Против открытой позиции"

    return ""


def _market_price_lines(
    *,
    direction: str,
    bid_price: NumericLike | None,
    ask_price: NumericLike | None,
) -> list[str]:
    bid = _format_price_usd(bid_price)
    ask = _format_price_usd(ask_price)

    if direction == "LONG" and ask != "—":
        return [f"Цена входа · {ask} (Ask)"]

    if direction == "SHORT" and bid != "—":
        return [f"Цена входа · {bid} (Bid)"]

    return []


def _format_price_usd(value: NumericLike | None) -> str:
    number = safe_float(value)

    if number is None:
        return "—"

    return f"${number:,.2f}".replace(",", " ")


def _alert_priority(*, confidence: float, repeat_count: int) -> str:
    if confidence >= 0.8 and repeat_count >= 3:
        return "HIGH"

    if confidence >= 0.6 or repeat_count >= 2:
        return "MEDIUM"

    return "LOW"


def _strength_label(priority: str) -> str:
    mapping = {
        "HIGH": "Сильный",
        "MEDIUM": "Средний",
        "LOW": "Слабый",
    }
    return mapping.get(priority.upper(), priority)


def _strength_bar(priority: str) -> str:
    mapping = {
        "HIGH": "●●●",
        "MEDIUM": "●●○",
        "LOW": "●○○",
    }
    return mapping.get(priority.upper(), "●○○")


def _signal_direction(signal: str) -> str:
    if signal == "BUY":
        return "Long"

    if signal == "SELL":
        return "Short"

    return "—"


def _direction_icon(direction: str) -> str:
    normalized = direction.upper()

    if normalized == "LONG":
        return "🟢"

    if normalized == "SHORT":
        return "🔴"

    return ""


def _format_symbol(symbol: str) -> str:
    if not symbol or symbol == "—":
        return "—"

    return symbol.split("_", 1)[0].split("/", 1)[0].upper()


def _dedupe_key(payload: JsonDict) -> str:
    is_aligned_signal = bool(payload.get("is_position_aligned_signal"))

    return (
        f"auto_signal_ready:"
        f"{payload.get('position_context')}:"
        f"{payload.get('symbol')}:"
        f"{payload.get('strategy')}:"
        f"{payload.get('signal')}:"
        f"{payload.get('decision_status')}:"
        f"aligned={is_aligned_signal}"
    )


def _as_json_list(value: object) -> JsonList:
    if isinstance(value, list):
        return value

    return []