from pathlib import Path
import json, base64, mimetypes
from playwright.sync_api import sync_playwright
root=Path(__file__).resolve().parents[1]/'web'
assets={}
for f in (root/'assets').iterdir():
  if f.is_file():
    mime=mimetypes.guess_type(str(f))[0] or 'application/octet-stream'
    assets[f.name]='data:'+mime+';base64,'+base64.b64encode(f.read_bytes()).decode()
css=(root/'v04.css').read_text().replace("url('assets/neon-wallpaper.jpg')",f"url('{assets['neon-wallpaper.jpg']}')")
js=(root/'app.js').read_text().replace("const path = name => A + name;","const path = name => window.__assetData[name] || A+name;").replace("const r=await fetch('./catalog.json');","const r={ok:true,json:async()=>window.__demoCatalog};")
# block SW registration, not relevant to DOM test
js=js.replace("navigator.serviceWorker.register('./sw.js').catch(()=>{});", "/* no service worker in inline test */")
html='<html><head><meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover"><style>'+css+'</style></head><body><div id="app"></div><div id="nav-root"></div><div id="overlay-root"></div></body></html>'
catalog=json.loads((root/'catalog.json').read_text())
with sync_playwright() as pw:
 browser=pw.chromium.launch(executable_path='/usr/bin/chromium',headless=True,args=['--no-sandbox'])
 for w,h in [(320,640),(390,844),(430,932),(820,1180),(1280,900)]:
  page=browser.new_page(viewport={'width':w,'height':h},device_scale_factor=1,has_touch=True,is_mobile=True,service_workers='block')
  errors=[]; page.on('pageerror',lambda e:errors.append(str(e)))
  page.goto('about:blank')
  page.set_content(html)
  page.evaluate('(arg)=>{window.__assetData=arg.assets;window.__demoCatalog=arg.catalog}',{'assets':assets,'catalog':catalog})
  page.evaluate(js)
  page.locator('.listing-card').first.wait_for()
  page.screenshot(path=f'/mnt/data/WetSlip_Web_v04_{w}.png',animations='disabled')
  snap=page.evaluate('''() => {const sc=document.querySelector('.page-scroll'),nav=document.querySelector('#nav-root');let a=nav.getBoundingClientRect(); return {width:document.documentElement.scrollWidth, bodyScroll:document.body.scrollHeight,viewH:innerHeight, navTop:a.top, navBottom:a.bottom, navH:a.height, scrollH:sc.scrollHeight,clientH:sc.clientHeight,bodyOverflow:getComputedStyle(document.body).overflow, cardW:document.querySelector('.listing-card').clientWidth,cardScrollW:document.querySelector('.listing-card').scrollWidth}}''')
  assert snap['width']<=w+1,('horizontal overflow',w,snap)
  assert snap['navBottom']<=h+1 and snap['navBottom']>=h-2,('nav mismatch',w,snap)
  pos0=page.locator('#nav-root').bounding_box()['y']
  page.evaluate("document.querySelector('.page-scroll').scrollTop=450")
  page.wait_for_timeout(100)
  pos1=page.locator('#nav-root').bounding_box()['y']
  assert abs(pos1-pos0)<1,('nav moves',w,pos0,pos1)
  page.get_by_role('button',name='Details für Weiße Spitzenpanty öffnen').click()
  assert page.get_by_role('dialog').count()==1
  assert page.get_by_text('Optionen · Vorschau').count()==1
  if w==390: page.screenshot(path='/mnt/data/WetSlip_Web_v04_detail.png',animations='disabled')
  # Scroll modal, navbar must not leak and page scroll remains locked.
  page.evaluate("document.querySelector('.modal-content').scrollTop=220")
  navBlocked=page.evaluate("getComputedStyle(document.getElementById('nav-root')).pointerEvents")
  assert navBlocked=='none',('nav enabled under overlay',w)
  page.locator('#overlay-root [data-add]').click()
  assert page.get_by_role('dialog',name='Wäschekorb').count()==1
  if w==390: page.screenshot(path='/mnt/data/WetSlip_Web_v04_cart.png',animations='disabled')
  page.get_by_role('button',name='Dialog schließen').click()
  page.evaluate("document.querySelector('.page-scroll').scrollTop=55")
  scrollBefore=page.evaluate("document.querySelector('.page-scroll').scrollTop")
  page.get_by_role('tab',name='Über mich').click()
  scrollAfter=page.evaluate("document.querySelector('.page-scroll').scrollTop")
  assert abs(scrollAfter-scrollBefore)<=1,('tab-scroll-jump',w,scrollBefore,scrollAfter)
  assert page.get_by_text('Über Vanessa').count()==1
  page.get_by_role('tab',name='Artikel').click()
  assert page.locator('.listing-card').count()==4
  # Seller status: independent photo, transparent ring, status cycling.
  assert page.locator('.avatar-photo').count()==1
  assert page.locator('.avatar-ring').count()==1
  assert page.locator('.online-dot.presence-online').count()==1
  page.locator('.online-pill').click()
  assert page.locator('.online-dot.presence-away').count()==1
  page.locator('.online-pill').click()
  assert page.locator('.online-dot.presence-offline').count()==1
  page.locator('.online-pill').click()
  assert page.locator('.online-dot.presence-online').count()==1
  assert not errors,(w,errors)
  print(w,snap,'ok')
  page.close()
 browser.close()

