"""Offline 5.3 example selection. Standard Python only. No MT5 or network calls."""
from pathlib import Path
from decimal import Decimal
import csv, hashlib, json

def load(path, digits):
    scale=10**digits
    with Path(path).open(encoding='utf-8-sig',newline='') as f: raw=list(csv.DictReader(f))
    rows=[]
    for row in raw:
        converted={'time':row['time_mt5']}
        for key in ('open','high','low','close'):
            value=Decimal(row[key])*scale; integer=int(value.to_integral_value())
            assert abs(value-integer)<Decimal('0.0001'), 'Price not on declared quote grid'
            converted[key]=integer
        assert converted['low']<=min(converted['open'],converted['close'])<=max(converted['open'],converted['close'])<=converted['high']
        rows.append(converted)
    return rows

def pivots(rows):
    result=[]
    for i in range(2,len(rows)-2):
        h,l=rows[i]['high'],rows[i]['low']
        high=h>max(r['high'] for r in rows[i-2:i]) and h>=max(r['high'] for r in rows[i+1:i+3])
        low=l<min(r['low'] for r in rows[i-2:i]) and l<=min(r['low'] for r in rows[i+1:i+3])
        if high==low:continue
        result.append({'i':i,'kind':'H' if high else 'L','price':h if high else l,'known':i+2})
    return result

def alternating(raw, known):
    out=[]
    for q in raw:
        if q['known']>known:break
        if not out or q['kind']!=out[-1]['kind']:out.append(q.copy())
        elif (q['kind']=='H' and q['price']>out[-1]['price']) or (q['kind']=='L' and q['price']<out[-1]['price']):out[-1]=q.copy()
    return out

def period(t):return '2026-01-01 00:00'<=t<='2026-09-30 23:59'

def pick_polarity(rows):
    raw=pivots(rows); candidates=[]
    for b in range(20,len(rows)-8):
        prior=[q for q in raw if q['kind']=='H' and q['known']<b]
        if not prior:continue
        anchor=prior[-1];lower=anchor['price']-20;upper=anchor['price']+20
        if not(rows[b]['close']>upper and rows[b-1]['close']<=upper):continue
        if not all(rows[j]['close']>upper for j in range(b+1,b+4)):continue
        retest=next((j for j in range(b+1,min(b+21,len(rows)-8)) if rows[j]['low']<=upper and rows[j]['high']>=lower and rows[j]['close']>upper),None)
        if retest is None:continue
        t=max(retest,b+3)
        if t-anchor['i']>32 or not period(rows[t]['time']):continue
        candidates.append({'id':'lab53-polarity','dataset':'USDJPY-H4.csv','digits':3,'assessment':t,'start':max(0,min(anchor['i']-4,t-20)),'end':t+8,'anchor':anchor,'breakout':b,'retest':retest,'lower':lower,'upper':upper})
    assert candidates, 'No eligible polarity example; do not relax the rules'
    return min(candidates,key=lambda q:(q['assessment'],q['breakout']))

def pick_warning(rows):
    raw=pivots(rows)
    for t in range(20,len(rows)-8):
        if not period(rows[t]['time']):continue
        known=alternating(raw,t-1)
        if len(known)<4:continue
        points=known[-4:];hs=[q for q in points if q['kind']=='H'];ls=[q for q in points if q['kind']=='L']
        if not(len(hs)==len(ls)==2 and hs[1]['price']>hs[0]['price'] and ls[1]['price']>ls[0]['price']):continue
        level=ls[-1]
        if t-points[0]['i']>32 or not(rows[t]['close']<level['price'] and rows[t-1]['close']>=level['price']):continue
        later=alternating(raw,t+8);new_lows=[q for q in raw if q['kind']=='L' and q['i']>=t and q['known']<=t+8 and q['price']<level['price']]
        return {'id':'lab53-structure-warning','dataset':'EURUSD-H4.csv','digits':5,'assessment':t,'start':max(0,min(points[0]['i']-4,t-20)),'end':t+8,'points':points,'level':level,'later_new_lows':new_lows,'later_points':later[-6:]}
    raise AssertionError('No eligible structure-warning example; do not relax the rules')

def run(folder):
    folder=Path(folder);meta=json.loads((folder/'lab53-cases.json').read_text(encoding='utf-8'))
    for source in meta['sources']:
        path=folder/source['file'];assert hashlib.sha256(path.read_bytes()).hexdigest()==source['sha256']
    selected=[pick_polarity(load(folder/'USDJPY-H4.csv',3)),pick_warning(load(folder/'EURUSD-H4.csv',5))]
    assert selected==meta['selected'], 'Selection differs from the frozen teaching cases'
    for case in selected:
        rows=load(folder/case['dataset'],case['digits']);t=case['assessment'];prefix=rows[:t+1]
        assert [q for q in pivots(prefix)]==[q for q in pivots(rows) if q['known']<=t]
        assert case['end']==t+8 and case['start']<t
    return {'pass':True,'cases':len(selected),'prefix_invariance':True,'trading_calls':0}

if __name__=='__main__': print(json.dumps(run(Path(__file__).parent),indent=2))
