from __future__ import annotations

from typing import Dict, List, Tuple

import numpy as np

from receipts.models import CompostStone

__all__ = ["CompostMarket"]


class CompostMarket:
    """Model compost remediation value using deterministic yield and NPV curves."""

    def compute_yield_curve(self, compost: CompostStone, days: int = 365) -> np.ndarray:
        """Return daily yield estimates for remediation value."""

        horizon = max(int(days), 1)
        bounty_0 = float(compost.bounty_credits)
        expected_impact: Dict[str, float] = compost.expected_impact or {}
        learning_rate = float(expected_impact.get("delta_clv", 0.02))

        fix_hours = compost.estimated_fix_hours if compost.estimated_fix_hours else 40.0
        fix_hours = max(float(fix_hours), 1.0)
        fix_rate = 1.0 / fix_hours

        t = np.linspace(0, horizon, horizon)
        fix_prob = 1 - np.exp(-fix_rate * t / 24.0)
        growth = np.power(1 + learning_rate, t)
        return bounty_0 * growth * fix_prob

    def compute_npv(self, compost: CompostStone, discount_rate: float = 0.05) -> float:
        """Integrate discounted yield curve to estimate net present value."""

        yield_curve = self.compute_yield_curve(compost)
        axis = np.arange(yield_curve.size)
        discount_factors = np.exp(-float(discount_rate) * axis / 365.0)
        npv = np.trapezoid(yield_curve * discount_factors)
        return float(npv)

    def rank_composts_by_npv(self, composts: List[CompostStone]) -> List[Tuple[str, float]]:
        """Return compost receipts ordered from highest to lowest NPV with deterministic ties."""

        rankings: List[Tuple[str, float]] = []
        for compost in composts:
            npv = self.compute_npv(compost)
            rankings.append((compost.receipt_id, npv))

        return sorted(rankings, key=lambda item: (-float(item[1]), item[0]))
