"""Generate plain-English budget recommendations from model results."""

from dataclasses import dataclass


@dataclass
class Recommendation:
    """A single budget recommendation."""

    rank: int
    action: str  # "INCREASE" or "DECREASE"
    channel: str
    change_amount: float  # absolute change per week
    current_spend: float
    optimal_spend: float
    roas: float
    reason: str


def generate_recommendations(
    current_allocation: dict[str, float],
    optimal_allocation: dict[str, float],
    roas_estimates: dict[str, float],
    expected_lift_pct: float,
) -> tuple[list[Recommendation], str]:
    """Generate ranked recommendations and executive summary.

    Args:
        current_allocation: Channel -> current weekly spend
        optimal_allocation: Channel -> optimal weekly spend
        roas_estimates: Channel -> ROAS estimate
        expected_lift_pct: Expected lift from optimization

    Returns:
        Tuple of (ranked recommendations list, executive summary text)
    """
    recommendations = []

    for channel in current_allocation:
        current = current_allocation[channel]
        optimal = optimal_allocation.get(channel, current)
        change = optimal - current
        roas = roas_estimates.get(channel, 0.0)

        if abs(change) < current * 0.05:  # Skip changes less than 5%
            continue

        if change > 0:
            action = "INCREASE"
            reason = _increase_reason(channel, roas, current, optimal)
        else:
            action = "DECREASE"
            reason = _decrease_reason(channel, roas, current, optimal)

        recommendations.append(
            Recommendation(
                rank=0,
                action=action,
                channel=channel,
                change_amount=abs(change),
                current_spend=current,
                optimal_spend=optimal,
                roas=roas,
                reason=reason,
            )
        )

    # Sort by absolute change amount descending
    recommendations.sort(key=lambda r: r.change_amount, reverse=True)
    for i, rec in enumerate(recommendations):
        rec.rank = i + 1

    summary = _generate_summary(recommendations, expected_lift_pct)

    return recommendations, summary


def _increase_reason(channel: str, roas: float, current: float, optimal: float) -> str:
    """Generate reason for increasing spend on a channel."""
    if roas > 2.5:
        return (
            f"Highest marginal ROAS ({roas:.1f}x) among all channels, "
            f"not yet saturated. Room to grow."
        )
    elif roas > 1.5:
        return (
            f"Strong ROAS ({roas:.1f}x) with headroom before saturation. "
            f"Incremental spend should be profitable."
        )
    else:
        return (
            f"Moderate ROAS ({roas:.1f}x) but currently underfunded relative to optimal. "
            f"Has room for profitable scale."
        )


def _decrease_reason(channel: str, roas: float, current: float, optimal: float) -> str:
    """Generate reason for decreasing spend on a channel."""
    pct_over = ((current - optimal) / optimal * 100) if optimal > 0 else 100
    if pct_over > 30:
        return (
            f"Heavily saturated — diminishing returns above "
            f"${optimal:,.0f}/week. Currently overspending by {pct_over:.0f}%."
        )
    else:
        return (
            f"Approaching saturation at current spend levels. "
            f"Marginal returns declining above ${optimal:,.0f}/week."
        )


def _generate_summary(recommendations: list[Recommendation], lift_pct: float) -> str:
    """Generate an executive summary paragraph."""
    if not recommendations:
        return (
            "Your current budget allocation is close to optimal. "
            "No significant changes recommended at this time."
        )

    increases = [r for r in recommendations if r.action == "INCREASE"]
    decreases = [r for r in recommendations if r.action == "DECREASE"]

    parts = []
    parts.append(
        f"Reallocating your budget could improve results by approximately {lift_pct:.1f}%."
    )

    if increases:
        top_increase = increases[0]
        parts.append(
            f"The biggest opportunity is {top_increase.channel}, which has a "
            f"{top_increase.roas:.1f}x ROAS and room to scale — "
            f"increase from ${top_increase.current_spend:,.0f} to "
            f"${top_increase.optimal_spend:,.0f}/week."
        )

    if decreases:
        top_decrease = decreases[0]
        parts.append(
            f"Meanwhile, {top_decrease.channel} is oversaturated at current spend. "
            f"Reducing from ${top_decrease.current_spend:,.0f} to "
            f"${top_decrease.optimal_spend:,.0f}/week frees up budget "
            f"without meaningful revenue loss."
        )

    return " ".join(parts)


def format_recommendation(rec: Recommendation) -> str:
    """Format a single recommendation as a readable string."""
    sign = "+" if rec.action == "INCREASE" else "-"
    return (
        f"#{rec.rank}  {rec.action} {rec.channel}  "
        f"{sign}${rec.change_amount:,.0f}/week  "
        f"(${rec.current_spend:,.0f} → ${rec.optimal_spend:,.0f})\n"
        f"    {rec.reason}"
    )


def format_all_recommendations(
    recommendations: list[Recommendation], summary: str
) -> str:
    """Format all recommendations as a readable report."""
    lines = ["=" * 60, "BUDGET OPTIMIZATION RECOMMENDATIONS", "=" * 60, "", summary, ""]

    for rec in recommendations:
        lines.append(format_recommendation(rec))
        lines.append("")

    return "\n".join(lines)
