"""
Pronostici del giorno — tre fasce per ogni partita, pronte per il sito web.

Per ogni partita in programma:
  - probabilità 1X2 dal MERCATO (la fonte più accurata che esista, come
    dimostrato dai backtest); se mancano le quote, dal modello DC
  - griglia dei punteggi dal modello DC, RISCALATA per essere coerente con
    le probabilità 1X2 di riferimento
  - dalla griglia, tutti i mercati derivati; per ciascuna fascia si sceglie
    la selezione con probabilità più alta dentro la banda:
        sicuro       p in [0.70, 0.88]   (quota equa 1.14 - 1.43)
        equilibrato  p in [0.50, 0.68]   (quota equa 1.47 - 2.00)
        azzardo      p in [0.20, 0.38]   (quota equa 2.63 - 5.00)

Output: tabella daily_picks nel DB (il sito legge da lì) + stampa.

Uso:
    python scripts/daily_picks.py                     # partite dei prossimi 3 giorni
    python scripts/daily_picks.py --date 2026-05-24 --settle   # demo su una data passata
"""

import argparse
import sys
from datetime import date, datetime, timedelta
from pathlib import Path

import numpy as np
import pandas as pd
import pymysql

import config

sys.path.insert(0, str(Path(__file__).resolve().parent))
import dixon_coles as dc
import impact
from score_tipsters import settle

TIERS = {"sicuro": (0.70, 0.88), "equilibrato": (0.50, 0.68), "azzardo": (0.20, 0.38)}

SCHEMA = """
CREATE TABLE IF NOT EXISTS daily_picks (
    id           INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    match_id     INT UNSIGNED NOT NULL,
    generated_at DATETIME NOT NULL,
    tier         ENUM('sicuro','equilibrato','azzardo') NOT NULL,
    market       VARCHAR(30) NOT NULL,
    selection    VARCHAR(40) NOT NULL,
    line         DECIMAL(4,1) NULL,
    label        VARCHAR(60) NOT NULL,
    probability  DECIMAL(6,4) NOT NULL,
    fair_odds    DECIMAL(7,3) NOT NULL,
    prob_source  ENUM('market','model') NOT NULL,
    outcome      ENUM('win','loss','void','unsettled') NOT NULL DEFAULT 'unsettled',
    UNIQUE KEY uq_pick (match_id, tier),
    CONSTRAINT fk_dp_match FOREIGN KEY (match_id) REFERENCES matches (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
"""


def candidates_from_grid(grid: np.ndarray) -> list[dict]:
    """Tutti i mercati derivati dalla griglia dei punteggi."""
    n = grid.shape[0]
    tot = np.add.outer(np.arange(n), np.arange(n))
    hg = np.arange(n)[:, None] * np.ones(n, dtype=int)
    ag = np.ones(n, dtype=int)[:, None] * np.arange(n)

    p1 = np.tril(grid, -1).sum()
    px = np.trace(grid)
    p2 = np.triu(grid, 1).sum()
    out = [
        {"market": "1x2", "selection": "1", "line": None, "label": "1 (casa)", "p": p1},
        {"market": "1x2", "selection": "X", "line": None, "label": "X (pareggio)", "p": px},
        {"market": "1x2", "selection": "2", "line": None, "label": "2 (ospite)", "p": p2},
        {"market": "double_chance", "selection": "1X", "line": None, "label": "Doppia chance 1X", "p": p1 + px},
        {"market": "double_chance", "selection": "X2", "line": None, "label": "Doppia chance X2", "p": px + p2},
        {"market": "double_chance", "selection": "12", "line": None, "label": "Doppia chance 12", "p": p1 + p2},
        {"market": "btts", "selection": "gol", "line": None, "label": "Gol (entrambe segnano)", "p": grid[(hg > 0) & (ag > 0)].sum()},
        {"market": "btts", "selection": "nogol", "line": None, "label": "NoGol", "p": grid[(hg == 0) | (ag == 0)].sum()},
    ]
    for line in (1.5, 2.5, 3.5):
        out.append({"market": "over_under", "selection": "over", "line": line,
                    "label": f"Over {line}", "p": grid[tot > line].sum()})
    for line in (2.5, 3.5, 4.5):
        out.append({"market": "over_under", "selection": "under", "line": line,
                    "label": f"Under {line}", "p": grid[tot < line].sum()})
    for lo, hi in ((1, 3), (2, 4), (1, 4), (2, 5)):
        out.append({"market": "multigol_total", "selection": f"{lo}-{hi}", "line": None,
                    "label": f"Multigol {lo}-{hi}", "p": grid[(tot >= lo) & (tot <= hi)].sum()})
    for lo, hi in ((1, 2), (1, 3)):
        out.append({"market": "multigol_home", "selection": f"{lo}-{hi}", "line": None,
                    "label": f"Multigol Casa {lo}-{hi}", "p": grid[(hg >= lo) & (hg <= hi)].sum()})
        out.append({"market": "multigol_away", "selection": f"{lo}-{hi}", "line": None,
                    "label": f"Multigol Ospite {lo}-{hi}", "p": grid[(ag >= lo) & (ag <= hi)].sum()})
    return out


def pick_tiers(cands: list[dict]) -> dict[str, dict]:
    picks = {}
    for tier, (lo, hi) in TIERS.items():
        in_band = [c for c in cands if lo <= c["p"] <= hi]
        if in_band:
            picks[tier] = max(in_band, key=lambda c: c["p"])
    return picks


def market_probs(row) -> tuple[float, float, float] | None:
    """Probabilità implicite normalizzate dalle quote pre-match disponibili."""
    for h, d, a in (("imp_h", "imp_d", "imp_a"),):
        if row[h] and float(row[h]) > 0:
            return float(row[h]), float(row[d]), float(row[a])
    oh, od, oa = row["avg_home"], row["avg_draw"], row["avg_away"]
    if oh and od and oa and float(oh) > 1:
        oh, od, oa = float(oh), float(od), float(oa)
        over = 1 / oh + 1 / od + 1 / oa
        return 1 / oh / over, 1 / od / over, 1 / oa / over
    return None


def main() -> int:
    parser = argparse.ArgumentParser(description="Genera i pronostici del giorno a tre fasce")
    parser.add_argument("--date", default=None,
                        help="Data specifica (YYYY-MM-DD); default: prossimi --days giorni")
    parser.add_argument("--days", type=int, default=3)
    parser.add_argument("--settle", action="store_true",
                        help="Regola subito gli esiti (per demo su date passate)")
    config.add_db_args(parser)
    args = parser.parse_args()

    conn = pymysql.connect(host=args.host, port=args.port, user=args.user,
                           password=args.password, database="tigertips")
    cur = conn.cursor()
    cur.execute(SCHEMA)
    conn.commit()

    if args.date:
        date_from = date_to = args.date
        cutoff = args.date          # niente look-ahead nella demo
    else:
        date_from = str(date.today())
        date_to = str(date.today() + timedelta(days=args.days))
        cutoff = None

    df = pd.read_sql("""
        SELECT m.id, l.code AS league, m.match_date, h.name AS home, a.name AS away,
               m.imp_prob_home AS imp_h, m.imp_prob_draw AS imp_d,
               m.imp_prob_away AS imp_a, m.avg_home, m.avg_draw, m.avg_away,
               m.home_goals AS hg, m.away_goals AS ag
        FROM matches m
        JOIN leagues l ON l.id = m.league_id
        JOIN teams h ON h.id = m.home_team_id
        JOIN teams a ON a.id = m.away_team_id
        WHERE m.match_date BETWEEN %s AND %s
        ORDER BY l.code, m.match_date
    """, conn, params=(date_from, date_to))
    if df.empty:
        print(f"Nessuna partita tra {date_from} e {date_to} "
              "(esegui sync_fixtures.py per caricare il calendario).")
        return 0
    print(f"Partite: {len(df)} ({date_from} -> {date_to})\n")

    models = {}
    n_saved = 0
    all_picks = []
    for r in df.itertuples(index=False):
        if r.league not in models:
            models[r.league] = impact.fit_current(conn, r.league, cutoff=cutoff)
        model = models[r.league]
        att_h, dfn_h = dc.team_params(model, r.home)
        att_a, dfn_a = dc.team_params(model, r.away)
        grid = dc.score_matrix(model, att_h, dfn_h, att_a, dfn_a)

        target = market_probs(r._asdict())
        source = "market" if target else "model"
        if target:
            grid = dc.rescale_to_1x2(grid, target)

        picks = pick_tiers(candidates_from_grid(grid))
        print(f"{r.league}  {r.home} - {r.away}  ({r.match_date})  [{source}]")
        for tier in ("sicuro", "equilibrato", "azzardo"):
            c = picks.get(tier)
            if c is None:
                print(f"   {tier:<12} (nessuna selezione in banda)")
                continue
            fair = 1 / c["p"]
            print(f"   {tier:<12} {c['label']:<24} p={c['p']:.1%}  "
                  f"quota equa {fair:.2f}")
            cur.execute("""
                INSERT INTO daily_picks
                    (match_id, generated_at, tier, market, selection, line,
                     label, probability, fair_odds, prob_source)
                VALUES (%s, NOW(), %s, %s, %s, %s, %s, %s, %s, %s)
                ON DUPLICATE KEY UPDATE
                    generated_at = NOW(), market = VALUES(market),
                    selection = VALUES(selection), line = VALUES(line),
                    label = VALUES(label), probability = VALUES(probability),
                    fair_odds = VALUES(fair_odds), prob_source = VALUES(prob_source)
            """, (int(r.id), tier, c["market"], c["selection"], c["line"],
                  c["label"], round(c["p"], 4), round(fair, 3), source))
            n_saved += 1
            all_picks.append({"tier": tier, "market": c["market"],
                              "selection": c["selection"], "line": c["line"],
                              "hg": r.hg, "ag": r.ag, "match_id": int(r.id)})
        conn.commit()

    print(f"\nPick salvate/aggiornate in daily_picks: {n_saved}")

    if args.settle and all_picks:
        sdf = pd.DataFrame(all_picks)
        sdf["outcome"] = sdf.apply(settle, axis=1)
        for r in sdf.dropna(subset=["outcome"]).itertuples(index=False):
            cur.execute("UPDATE daily_picks SET outcome = %s "
                        "WHERE match_id = %s AND tier = %s",
                        (r.outcome, r.match_id, r.tier))
        conn.commit()
        print("\n=== Esiti (demo) ===")
        for tier, grp in sdf.dropna(subset=["outcome"]).groupby("tier"):
            wins = (grp["outcome"] == "win").sum()
            valid = (grp["outcome"] != "void").sum()
            print(f"  {tier:<12} {wins}/{valid} vinte ({wins / valid:.0%})")

    conn.close()
    return 0


if __name__ == "__main__":
    sys.exit(main())
