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

from __future__ import annotations

from src.core.numbers import safe_float
from src.notifications.models import NotificationMessage
from src.runtime_events.event_types import RuntimeEventType
from src.runtime_events.models import RuntimeEvent


def build_execution_notification(event: RuntimeEvent) -> NotificationMessage | None:
    if event.event_type == RuntimeEventType.POSITION_OPENED:
        return _build_position_opened(event)

    if event.event_type == RuntimeEventType.POSITION_CLOSED:
        return _build_position_closed(event)

    if event.event_type == RuntimeEventType.POSITION_FLIPPED:
        return _build_position_flipped(event)

    if event.event_type == RuntimeEventType.POSITION_FLIP_BLOCKED:
        return _build_flip_blocked(event)

    return None


def _build_position_opened(event: RuntimeEvent) -> NotificationMessage:
    payload = event.payload

    symbol = _format_symbol(payload.get("symbol"))
    side_raw = str(payload.get("side") or "—").upper()
    side = side_raw.title()
    side_icon = _side_icon(side_raw)

    leverage = _format_leverage(payload.get("leverage"))
    entry_price = _format_price(payload.get("entry_price"))
    size = _format_size(payload.get("size"))

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

    priority = _alert_priority(
        confidence=confidence,
        repeat_count=repeat_count,
    )

    semantic_lines = payload.get("semantic_lines") or []

    lines = [
        f"🧾 Открытие · <b>{symbol}</b> {side_icon} {side}",
        f"{_strength_bar(priority)} {_strength_label(priority)} · {confidence:.2f}",
        f"Серия {signal} · ×{repeat_count}",
    ]

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

    lines.extend(
        [
            f"Цена входа · ${entry_price}",
            f"Размер · {size}",
            f"Плечо · {leverage}",
        ]
    )

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


def _build_position_closed(event: RuntimeEvent) -> NotificationMessage:
    payload = event.payload

    symbol = _format_symbol(payload.get("symbol"))
    side_raw = str(payload.get("side") or "—").upper()
    side = side_raw.title()
    side_icon = _side_icon(side_raw)

    entry_price = _format_price(payload.get("entry_price"))
    exit_price = _format_price(payload.get("exit_price"))

    pnl_value = safe_float(payload.get("pnl")) or 0.0
    pnl_text = _format_pnl_amount(pnl_value)

    risk_reason = _human_close_reason(payload.get("risk_reason"))

    pnl_icon = "🟢" if pnl_value >= 0 else "🔴"
    pnl_label = "Прибыль" if pnl_value >= 0 else "Убыток"

    lines = [
        f"💰 Закрытие · <b>{symbol}</b> {side_icon} {side}",
        f"<b>{pnl_label}</b> {pnl_icon} {pnl_text}",
        f"Вход · ${entry_price}",
        f"Выход · ${exit_price}",
    ]

    if risk_reason:
        lines.append(f"Причина · {risk_reason}")

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


def _build_position_flipped(event: RuntimeEvent) -> NotificationMessage:
    payload = event.payload

    symbol = _format_symbol(payload.get("symbol"))

    old_side_raw = str(payload.get("old_side") or "—").upper()
    new_side_raw = str(payload.get("new_side") or payload.get("side") or "—").upper()

    old_side = old_side_raw.title()
    new_side = new_side_raw.title()

    old_icon = _side_icon(old_side_raw)
    new_icon = _side_icon(new_side_raw)

    exit_price = _format_price(payload.get("exit_price"))
    new_entry_price = _format_price(payload.get("new_entry_price"))

    pnl_value = safe_float(payload.get("pnl")) or 0.0
    pnl_text = _format_pnl_amount(pnl_value)

    pnl_icon = "🟢" if pnl_value >= 0 else "🔴"
    pnl_label = "Прибыль" if pnl_value >= 0 else "Убыток"

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

    priority = _alert_priority(
        confidence=confidence,
        repeat_count=repeat_count,
    )

    semantic_lines = payload.get("semantic_lines") or []

    lines = [
        f"🔄 Разворот · <b>{symbol}</b> {old_icon} {old_side} → {new_icon} {new_side}",
        f"<b>{pnl_label}</b> {pnl_icon} {pnl_text}",
        f"Закрытие · ${exit_price}",
        f"Новый вход · ${new_entry_price}",
        "",
        f"{_strength_bar(priority)} {_strength_label(priority)} · {confidence:.2f}",
        f"Серия {signal} · ×{repeat_count}",
    ]

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

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


def _build_flip_blocked(event: RuntimeEvent) -> NotificationMessage:
    payload = event.payload

    symbol = _format_symbol(payload.get("symbol"))
    signal = str(payload.get("signal") or "").upper()
    confidence = safe_float(payload.get("confidence")) or 0.0
    reason = str(payload.get("reason") or "Flip заблокирован")
    position_side = str(payload.get("position_side") or "—").title()

    if signal == "BUY":
        target_side = "Long"
        icon = "🟢"
    elif signal == "SELL":
        target_side = "Short"
        icon = "🔴"
    else:
        target_side = "—"
        icon = "⚪️"

    text = (
        f"<b>Flip отменён {symbol} {icon} {target_side}</b>\n\n"
        f"Текущая позиция · {position_side}\n"
        f"Сила сигнала · {confidence:.2f}\n"
        f"Причина · {reason}"
    )

    return NotificationMessage(
        title=event.title,
        text=text,
        priority=event.priority,
        dedupe_key=event.dedupe_key,
    )


def _side_icon(side: str) -> str:
    normalized = str(side or "").upper()

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

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

    return "⚪️"


def _format_pnl_amount(value: float) -> str:
    amount = f"$ {abs(value):,.2f}".replace(",", " ").rstrip("0").rstrip(".")

    if value > 0:
        return f"+{amount}"

    if value < 0:
        return f"−{amount}"

    return "$ 0"


def _human_close_reason(value: object) -> str:
    mapping = {
        "STOP_LOSS": "Stop Loss",
        "TAKE_PROFIT": "Take Profit",
        "MAX_LOSS": "Max Loss",
        "AUTONOMOUS_EXIT": "Autonomous Exit",
        "TRAILING_STOP": "Trailing Stop",
        "PROFIT_LOCK": "Profit Lock",
        "BREAK_EVEN": "Break Even",
        "LIFECYCLE_EXIT": "Lifecycle Exit",
        "CONVICTION_BROKEN": "Conviction Broken",
        "FATIGUE_EXIT": "Fatigue Exit",
        "MOMENTUM_EXIT": "Momentum Exit",
        "DEGRADATION_EXIT": "Degradation Exit",
        "GIVEBACK_PROTECTION": "Giveback Protection",
        "GIVEBACK_MOMENTUM_REVERSAL": "Giveback Momentum Reversal",
        "GIVEBACK_FATIGUE_EXIT": "Giveback Fatigue Exit",
        "GIVEBACK_REVERSAL_RISK": "Giveback Reversal Risk",
        "TIME_DECAY_EXIT": "Time Decay",
        "TIME_DECAY_FATIGUE_EXIT": "Time Decay Fatigue",
        "TIME_DECAY_ADVERSE_MOMENTUM": "Time Decay Momentum",
        "TIME_DECAY_DEGRADED_MARKET": "Time Decay Market",
        "TIME_DECAY_CONTEXT_DECAY": "Time Decay Context",
    }

    return mapping.get(str(value or ""), "")


def _format_symbol(value: object) -> str:
    symbol = str(value or "—")

    if not symbol or symbol == "—":
        return "—"

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


def _format_leverage(value: object) -> str:
    number = safe_float(value)

    if number is None:
        return "—"

    return f"x{number:g}"


def _format_price(value: object) -> str:
    number = safe_float(value)

    if number is None:
        return "—"

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


def _format_size(value: object) -> str:
    number = safe_float(value)

    if number is None:
        return "—"

    return f"{number:.8f}".rstrip("0").rstrip(".")


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(), "●○○")