from __future__ import annotations
import math, time
import numpy as np
from scipy.stats import poisson
from database.manager import DatabaseManager
from agents.analyzer_agent import AnalyzerAgent

class PredictorAgent:
    def __init__(self, db: DatabaseManager) -> None:
        self.db = db
        self.analyzer = AnalyzerAgent(db)

    async def _rates(self, team: str, limit: int = 25) -> tuple[float, float]:
        rows = await self.db.last_matches_for_team(team, limit=limit)
        if not rows:
            return (1.25, 1.25)
        scored, conceded = [], []
        for m in rows:
            if m.home_score is None or m.away_score is None:
                continue
            if m.home_team == team:
                scored.append(m.home_score); conceded.append(m.away_score)
            else:
                scored.append(m.away_score); conceded.append(m.home_score)
        if not scored:
            return (1.25, 1.25)
        return (float(np.mean(scored)), float(np.mean(conceded)))

    def _outcome_probs(self, lam_h: float, lam_a: float, max_goals: int = 8) -> tuple[float,float,float]:
        ph=pd=pa=0.0
        for hg in range(max_goals+1):
            for ag in range(max_goals+1):
                p = float(poisson.pmf(hg, lam_h) * poisson.pmf(ag, lam_a))
                if hg>ag: ph+=p
                elif hg==ag: pd+=p
                else: pa+=p
        s = ph+pd+pa
        if s<=0: return (1/3,1/3,1/3)
        return (ph/s, pd/s, pa/s)

    def _confidence(self, ph: float, pd: float, pa: float) -> float:
        # entropy-based confidence
        eps=1e-12
        H = -(ph*math.log(ph+eps)+pd*math.log(pd+eps)+pa*math.log(pa+eps))
        Hmax = math.log(3)
        return float(max(0.0, min(1.0, 1.0 - H/Hmax)))

    async def predict_for_match(self, match) -> dict:
        hs, hc = await self._rates(match.home_team)
        as_, ac = await self._rates(match.away_team)

        # Form factor (points per game last 5)
        hf = await self.analyzer.team_form(match.home_team, n=5)
        af = await self.analyzer.team_form(match.away_team, n=5)
        hf_ppg = (hf["points"]/hf["n"]) if hf["n"] else 1.0
        af_ppg = (af["points"]/af["n"]) if af["n"] else 1.0

        # Home advantage (small, constant)
        home_adv = 0.12

        lam_h = max(0.2, 0.55*hs + 0.45*ac) * (1.0 + home_adv) * (0.9 + 0.1*hf_ppg)
        lam_a = max(0.2, 0.55*as_ + 0.45*hc) * (0.9 + 0.1*af_ppg)

        ph, pd, pa = self._outcome_probs(lam_h, lam_a)
        conf = self._confidence(ph, pd, pa)

        return {
            "match_id": match.id,
            "model": "poisson+form",
            "p_home_win": float(ph),
            "p_draw": float(pd),
            "p_away_win": float(pa),
            "exp_home_goals": float(lam_h),
            "exp_away_goals": float(lam_a),
            "confidence": float(conf),
            "created_ts": int(time.time()),
        }
