import sys,random,hashlib,json
from pathlib import Path
sys.path.insert(0,str(Path(__file__).resolve().parents[3]))
from hesper.laws.terrain import gather
from hesper.tests.test_gather import GatherPhase,TURN
rng=random.Random(79)
for case in range(10000):
 ps=[dict(action_id=str(i),arrived_turn=rng.choice([None,1,2,3]),want=rng.randrange(17)) for i in range(rng.randrange(1,9))];qty=rng.randrange(65)
 expected={p['action_id']:0 for p in ps};left=qty
 for arrival in [1,2,3,None]:
  group=[p for p in ps if p['arrived_turn']==arrival]
  while left and any(expected[p['action_id']]<p['want'] for p in group):
   hungry=[p for p in group if expected[p['action_id']]<p['want']]
   p=min(hungry,key=lambda p:expected[p['action_id']]);expected[p['action_id']]+=1;left-=1
 actual=gather.allocate(qty,ps)
 assert actual==expected,(case,ps,qty,actual,expected)
 assert sum(actual.values())==min(qty,sum(p['want'] for p in ps))
print('10000 independent water-fill/conservation/demand-cap cases pass')
f=GatherPhase();f.setUp()
a=f.citizen('A',1,0,arrived=3);b=f.citizen('B',1,0,arrived=3)
ids=sorted(['aaaaaaaaaaaa','bbbbbbbbbbbb'],key=lambda a:hashlib.sha256(('seedrq_'+a).encode()).hexdigest())
f.queue(a,1,1000,ids[1]);f.queue(b,1,2000,ids[0]);f.conn.execute('UPDATE tiles SET resource_qty=1 WHERE x=1 AND y=0')
r=gather.run(f.conn,TURN,seed='seed');print('LOT hashfirst',ids[0],'firstsubmitted',ids[1],'grants',[(x['action_id'],x['yielded']) for x in r]);assert r[0]['yielded']==1 and r[0]['action_id']==ids[1]
f.doCleanups()
f=GatherPhase();f.setUp();a=f.citizen('A',1,0,arrived=3);b=f.citizen('B',1,0,arrived=3)
f.queue(a,1,1000,'a');f.queue(b,1,2000,'b')
f.conn.execute("UPDATE things SET state_json=json_set(state_json,'$.worn_turn','bad') WHERE owner_player=? AND thing_id != (SELECT avatar_thing_id FROM players WHERE player_id=?)",(a,a))
r=gather.run(f.conn,TURN,seed='seed');left=f.tile(1,0)['resource_qty'];print('ROLLBACK',[(x['action_id'],x['outcome'],x.get('yielded')) for x in r], 'left',left);print('CONSERVATION initial4, yielded',sum(x.get('yielded',0) for x in r),'left',left)
assert r[0]['outcome']=='action_failed' and sum(x.get('yielded',0) for x in r)==2 and left==0
f.doCleanups()
