"""Does Pinnacle price COLD-START fixtures worse than settled ones?

This is a pre-test for the SoFIFA question, run BEFORE spending any effort
acquiring squad-rating data.

THE LOGIC. Every strength feature we have tested (Elo, rolling form) is derived
from RESULTS, so it is blind at cold start: a newly promoted team, a season
opener, a squad rebuilt in the transfer window. Scout-assessed player ratings
(SoFIFA / EA) are genuinely different in provenance -- they carry information
about a squad that has not played yet. That is the one real gap in what we have
tested.

But squad ratings can only help if THE MARKET is also weak there. Pinnacle reads
the same team sheets. So the question that decides whether to scrape anything is
not "are ratings informative" but "is the closing line measurably worse on cold-
start fixtures than on settled ones?"

  - If the line is equally sharp at cold start -> no room. Do not scrape.
  - If the line degrades materially -> a gap exists, and squad ratings are the
    obvious candidate to fill it.

COLD START is measured as matches played by BOTH teams in the current season
(season = calendar year boundary is wrong for European leagues, so we use a
rolling "matches since a >60-day gap for that team", which detects a real
off-season break in any calendar).

Metric is LOG LOSS of the devigged closing line against the realised result.
Lower is better. The comparison is like-for-like on the same leagues.
"""
import csv
import math
import sys
from collections import defaultdict
from datetime import datetime

sys.path.insert(0, r'E:\soccer\research')
sys.path.insert(0, r'E:\soccer\main')
import elo_model_test as E
import nonprice_edge_test as T       # odds loader used by elo_model_test
import daily_signals as DS

OFFSEASON_GAP_DAYS = 60


def devig(o):
    r = [1.0 / x for x in o]
    s = sum(r)
    return [x / s for x in r]


def main():
    fx = E.load_fixtures()
    print(f'{len(fx)} fixtures with results')

    # matches-into-season per team, via off-season gap detection
    last, cnt = {}, defaultdict(int)
    for f in fx:
        for side in ('home', 'away'):
            t = f[side]
            if t in last and (f['date'] - last[t]).days > OFFSEASON_GAP_DAYS:
                cnt[t] = 0
            last[t] = f['date']
        f['mp_h'], f['mp_a'] = cnt[f['home']], cnt[f['away']]
        cnt[f['home']] += 1
        cnt[f['away']] += 1

    odds = T.load_odds()
    rows = []
    for f in fx:
        key = (f['date'], T.norm(DS.fdco_name(f['home'])), T.norm(DS.fdco_name(f['away'])))
        hit = odds.get(key)
        if not hit:
            continue
        p, res = hit          # devigged probs + result LETTER ('H'/'D'/'A')
        i = T.IDX.get(res)
        if i is None:
            continue
        rows.append({'ll': -math.log(max(p[i], 1e-12)),
                     'mp': min(f['mp_h'], f['mp_a']), 'div': f['div']})
    print(f'{len(rows)} matched to Pinnacle closing odds\n')

    def blk(name, sub):
        if len(sub) < 50:
            print(f'  {name:26s} n={len(sub):5d}  (too few)')
            return
        ll = sum(x['ll'] for x in sub) / len(sub)
        se = (sum((x['ll'] - ll) ** 2 for x in sub) / (len(sub) - 1) / len(sub)) ** 0.5
        print(f'  {name:26s} n={len(sub):5d}  log loss {ll:.5f}  +/- {se:.5f}')
        return ll, se, len(sub)

    print('PINNACLE CLOSING LINE ACCURACY BY MATCHES-INTO-SEASON')
    print('(lower log loss = sharper. If cold start is NOT worse, squad ratings')
    print(' cannot help, because the market already knows.)')
    buckets = [(0, 1, 'season opener (0)'), (1, 3, 'matches 1-2'),
               (3, 6, 'matches 3-5'), (6, 12, 'matches 6-11'),
               (12, 999, 'matches 12+ (settled)')]
    res = {}
    for lo, hi, nm in buckets:
        r = blk(nm, [x for x in rows if lo <= x['mp'] < hi])
        if r:
            res[nm] = r

    early = [x for x in rows if x['mp'] < 3]
    late = [x for x in rows if x['mp'] >= 12]
    if len(early) > 50 and len(late) > 50:
        le = sum(x['ll'] for x in early) / len(early)
        ll_ = sum(x['ll'] for x in late) / len(late)
        se = ((sum((x['ll'] - le) ** 2 for x in early) / (len(early) - 1) / len(early))
              + (sum((x['ll'] - ll_) ** 2 for x in late) / (len(late) - 1) / len(late))) ** 0.5
        d = le - ll_
        print(f'\n  cold start (<3 played) minus settled (12+): {d:+.5f} '
              f'+/- {se:.5f}  -> t = {d/se:+.2f}')
        print('  positive t means the line IS worse when teams are cold.')


if __name__ == '__main__':
    main()
