"""
The Buy/Sell engine's public entry point (spec §27/§28/§55). Combines the score-table
recommendation with sell-trigger overrides, and returns a fully explainable result: the exact
band values and the exact triggers that produced it (WHY / RISKS).
"""
from __future__ import annotations

from dataclasses import dataclass, field
from typing import Optional

from app.engines.recommendation.bands import Recommendation, recommendation_from_table, risk_band_from_score
from app.engines.recommendation.sell_triggers import (
    SellTriggerInputs, evaluate_sell_triggers, sell_ceiling_from_severity,
)


@dataclass(frozen=True)
class RecommendationResult:
    recommendation: Recommendation
    table_recommendation: Recommendation
    sell_ceiling: Optional[Recommendation]
    triggers_fired: list[str]
    trigger_severity: int
    inputs: dict = field(default_factory=dict)

    @property
    def why(self) -> dict:
        return {k: v for k, v in self.inputs.items() if k in ("overall_score", "margin_of_safety", "risk_score", "expected_cagr_base")}

    @property
    def risks(self) -> list[str]:
        return list(self.triggers_fired)


def compute_recommendation(
    overall_score: Optional[float],
    margin_of_safety: Optional[float],
    risk_score_0_100: Optional[float],
    expected_cagr_base: Optional[float],
    sell_trigger_inputs: SellTriggerInputs,
) -> RecommendationResult:
    table_rec = recommendation_from_table(overall_score, margin_of_safety, risk_score_0_100, expected_cagr_base)
    fired, severity = evaluate_sell_triggers(sell_trigger_inputs)
    ceiling = sell_ceiling_from_severity(severity)

    final = table_rec if ceiling is None else Recommendation(min(int(table_rec), int(ceiling)))

    return RecommendationResult(
        recommendation=final,
        table_recommendation=table_rec,
        sell_ceiling=ceiling,
        triggers_fired=fired,
        trigger_severity=severity,
        inputs={
            "overall_score": overall_score, "margin_of_safety": margin_of_safety,
            "risk_score": risk_score_0_100, "risk_band": risk_band_from_score(risk_score_0_100).name,
            "expected_cagr_base": expected_cagr_base,
        },
    )
