from pathlib import Path
from lupa.luajit21 import LuaRuntime
import json,tempfile,os
R=Path(__file__).resolve().parents[1]
def lua(L,v):
 if isinstance(v,dict):return L.table_from({k:lua(L,x)for k,x in v.items()})
 if isinstance(v,list):return L.table_from([lua(L,x)for x in v])
 return v
L=LuaRuntime(unpack_returned_tuples=True);L.globals().SOURCE=str(R/'src')
L.globals().FIXTURE=lua(L,json.loads((R/'tests/three-mechs-identities.json').read_text()))
L.globals().LIVE_API=lua(L,json.loads((R/'tests/live-api-t1-failure.json').read_text())['api_functions'])
prefix=(R/'tests/test_spatial.lua').read_text().split("local runtime=load('spatial_runtime')(sr,N,Z,policy)")[0]
script=r'''
sr.GameSession.unit_synchronizer=function()return nil end
sr.GameSession.in_session=function()return true end
sr.GameSession.objects_owned_by=function()return {10}end
sr.GameSession.game_object_is_type=function()return true end
sr.GameSession.game_object_field=function()return 20 end
sr.Gui.resolution=function()return 1920,1080 end
local entities={};for i=1,384 do entities[i]=9000+i end
sr.World.units=function()error('old full-world unit scan forbidden')end
sr.World.entities=function()return entities end
sr.EntityManager={alive=function(e)C(e>=9001 and e<=9384);return true end,unit_component=function(w)C(w==ctl.world);return 'UC'end}
sr.UnitComponent={instances=function(uc,e)C(uc=='UC');return 0 end,unit=function(uc,e)C(uc=='UC');return e end}

sr.Unit.id=function(u)return u end
sr.Unit.resource_name=function(u)return '1234567890abcdef' end
sr.Unit.world=function()return ctl.world end
local Reader={sample=function()return {vehicle=FIXTURE.mechs[1],model=Z.models[FIXTURE.mechs[1].resource],hull=1800,hull_max=1800,hull_valid=true,zones={}}end}
local Arm={discover=function()return {},'AMBIGUOUS',metadata()end,read=function()return {hp=800,max=800,zones={}}end,verify=function()return true end}
local D={mode='MECH',clear=function()end,reset=function()end,ensure=function()return true end,draw=function(w,h,v)_G.VIEW=v end}
CowboyBingusModLoader={api=1};update=function()return 'old',nil,7 end
local P=load('bridge_probe')(sr)
local S=load('hud')(sr,N,Reader,function()return{}end,Z,function()return {debug=true,poll=.25,spatial=true}end,{},function()return D end,Arm,load('json'),load('spatial_runtime')(sr,N,Z,policy),P)
-- Disable CPU timing only in this deterministic cadence fixture, not production.
local real_clock=os.clock;os.clock=function()return 0 end
for i=1,4 do local a,b,c=update(.25);C(a=='old'and b==nil and c==7);C(not S.arms and S.arm_association==nil,'probe must not supply displayed arms')end
os.clock=real_clock
C(P.runs==1,'384 entities must finish in 4 polls; not 1-second retry cadence')
for i=1,8 do update(.25)end
C(P.runs==1,'production HUD must call actual probe and obey cooldown')
return checks
'''
with tempfile.TemporaryDirectory()as tmp:
 os.environ['APPDATA']=tmp;d=Path(tmp)/'Arrowhead/Helldivers2';d.mkdir(parents=True)
 checks=L.execute(prefix+script)
 files=list(d.glob('mech_hud_bridge_*.json'));assert len(files)==1
 report=json.loads(files[0].read_text());assert report['status']=='COMPLETE_OBSERVATION_NOT_MAPPING' and report['scanned']==384
 assert 'BRIDGE_EVIDENCE' in (d/'mech_hud.log').read_text()
r={'checks':checks,'production_hud_probe_wiring':True,'four_poll_384_entity_scan':True,'report_written':True,'ambiguous_arms_remain_hidden':True,'original_callback_preserved':True,'game_calls':0}
(R/'validation/bridge-hud-tests.json').write_text(json.dumps(r,indent=2)+'\n');print(json.dumps(r,indent=2))
