from pathlib import Path
from datetime import datetime, timezone
from playwright.sync_api import sync_playwright
import json, os, platform
from bs4 import BeautifulSoup

ROOT = Path.cwd()
OUT = ROOT / 'outputs/rita-journey-20261002/evidence/luna-legacy-fix'
STAGED = ROOT / 'outputs/rita-journey-20261002/legacy/staged'
index = BeautifulSoup((STAGED / 'index.html').read_text(), 'html.parser')
EXPECTED_TITLES = {}
for item in index.select('iframe'):
    child = BeautifulSoup((STAGED / item.get('src')).read_text(), 'html.parser')
    EXPECTED_TITLES[item.get('src')] = child.title.get_text(strip=True) if child.title else ''
URL = 'https://review.clientsflow.hu/komplex-rita-funnel-2026-09-26-v1/'
blocked = []
result = {
    'url': URL,
    'checkedAt': datetime.now(timezone.utc).isoformat(),
    'purpose': 'Read-only browser diagnosis. Every non-GET/HEAD request was aborted; no provider write was allowed.',
    'environment': {'platform': platform.platform(), 'viewport': {'width': 1440, 'height': 1000}},
}

def guard(route):
    req = route.request
    if req.method not in ('GET', 'HEAD'):
        blocked.append({'method': req.method, 'url': req.url})
        route.abort()
    else:
        route.continue_()

with sync_playwright() as p:
    browser = p.chromium.launch(headless=True, executable_path='/Applications/Google Chrome.app/Contents/MacOS/Google Chrome')
    context = browser.new_context(viewport={'width': 1440, 'height': 1000}, device_scale_factor=1)
    context.route('**/*', guard)
    page = context.new_page()
    page.set_default_timeout(12000)
    response = page.goto(URL, wait_until='domcontentloaded', timeout=45000)
    page.wait_for_function("document.body && document.body.getAttribute('data-legacy-comment-master') === 'komplex-rita-funnel-20260926-master'", timeout=20000)
    result['httpStatus'] = response.status if response else None
    result['dpr'] = page.evaluate('devicePixelRatio')
    result['initial'] = page.locator('iframe').evaluate_all("frames => frames.map((f,i) => ({index:i,src:f.getAttribute('src'),frameUrl:f.contentDocument && f.contentDocument.URL,readyState:f.contentDocument && f.contentDocument.readyState,hasBody:!!(f.contentDocument && f.contentDocument.body),hasRoot:!!(f.contentDocument && f.contentDocument.getElementById('comment-html-root')),openDetails:Array.from((function*(n){for(let p=n.parentElement;p;p=p.parentElement)if(p.tagName==='DETAILS')yield p})(f)).map(d=>({id:d.id,open:d.open}))}))")
    result['initialSummary'] = {
        'iframeCount': len(result['initial']),
        'actualSrcDocuments': sum(1 for x in result['initial'] if x['frameUrl'] and x['frameUrl'].startswith(URL)),
        'aboutBlankDocuments': sum(1 for x in result['initial'] if x['frameUrl'] == 'about:blank'),
        'hasBodyFalsePositiveCount': sum(1 for x in result['initial'] if x['hasBody'] and not x['hasRoot']),
    }
    page.locator('iframe').evaluate_all("frames => frames.forEach(f => { for (let p=f.parentElement; p; p=p.parentElement) if (p.tagName==='DETAILS') p.open=true; f.loading='eager'; })")
    try:
        page.wait_for_function("""expectedTitles => Array.from(document.querySelectorAll('iframe')).length === 29 && Array.from(document.querySelectorAll('iframe')).every(f => {
          try {
            const expected = new URL(f.getAttribute('src'), document.baseURI);
            const doc = f.contentDocument;
            if (!doc || !doc.body || doc.readyState !== 'complete') return false;
            const actual = new URL(doc.URL);
            const canonical = path => path.endsWith('.html') ? path.slice(0, -5) : path;
            return expected.origin === location.origin && actual.origin === expected.origin && canonical(actual.pathname) === canonical(expected.pathname) && actual.search === expected.search && doc.title === expectedTitles[f.getAttribute('src')];
          } catch (_) { return false; }
        })""", arg=EXPECTED_TITLES, timeout=50000)
        result['allActualDocumentsReady'] = True
    except Exception as e:
        result['allActualDocumentsReady'] = False
        result['allActualDocumentsWaitError'] = str(e).splitlines()[0]
    try:
        page.wait_for_function("Array.from(document.querySelectorAll('iframe')).every(f => f.contentDocument && f.contentDocument.getElementById('comment-html-root'))", timeout=20000)
        result['allRootsReady'] = True
    except Exception as e:
        result['allRootsReady'] = False
        result['allRootsWaitError'] = str(e).splitlines()[0]
    result['frames'] = page.locator('iframe').evaluate_all("""(frames, expectedTitles) => frames.map((f,i) => {
      const expected = new URL(f.getAttribute('src'), document.baseURI);
      const doc = f.contentDocument;
      let actual = null;
      try { actual = doc ? new URL(doc.URL) : null; } catch (_) {}
      const root = doc && doc.getElementById('comment-html-root');
      const suppression = doc && doc.querySelector('style[data-legacy-suppression="komplex-rita-funnel-20260926-master"]');
      const canonical = path => path.endsWith('.html') ? path.slice(0, -5) : path;
      return {index:i,src:f.getAttribute('src'),frameTitle:f.title,documentTitle:doc && doc.title,expectedStageTitle:expectedTitles[f.getAttribute('src')],expectedUrl:expected.href,actualUrl:actual && actual.href,readyState:doc && doc.readyState,bodyTextStart:doc && doc.body ? doc.body.innerText.slice(0,120) : null,documentMatchesExpected:!!(actual && actual.origin===expected.origin && canonical(actual.pathname)===canonical(expected.pathname) && actual.search===expected.search),matchesStageTitle:!!(doc && doc.title===expectedTitles[f.getAttribute('src')]),root:!!root,suppressionMarker:!!suppression,suppressionText:suppression && suppression.textContent,rootDisplay:root ? doc.defaultView.getComputedStyle(root).display : null,rootVisibility:root ? doc.defaultView.getComputedStyle(root).visibility : null,rootPointerEvents:root ? doc.defaultView.getComputedStyle(root).pointerEvents : null};
    })""", EXPECTED_TITLES)
    result['frameSummary'] = {
        'expected': 29,
        'matchingFinalDocuments': sum(1 for x in result['frames'] if x['documentMatchesExpected']),
        'aboutBlank': sum(1 for x in result['frames'] if x['actualUrl'] == 'about:blank'),
        'roots': sum(1 for x in result['frames'] if x['root']),
        'suppressionMarkers': sum(1 for x in result['frames'] if x['suppressionMarker']),
        'fullySuppressed': sum(1 for x in result['frames'] if x['suppressionMarker'] and x['rootDisplay']=='none' and x['rootVisibility']=='hidden' and x['rootPointerEvents']=='none'),
        'matchingStageTitles': sum(1 for x in result['frames'] if x['matchesStageTitle']),
        'unmatched': [x['src'] for x in result['frames'] if not x['documentMatchesExpected']],
        'missingRoots': [x['src'] for x in result['frames'] if x['documentMatchesExpected'] and not x['root']],
        'unsuppressed': [x['src'] for x in result['frames'] if x['documentMatchesExpected'] and x['root'] and not (x['suppressionMarker'] and x['rootDisplay']=='none' and x['rootVisibility']=='hidden' and x['rootPointerEvents']=='none')],
    }
    # Read the outer toolbar geometry at the header and at the actual deep appendix anchor.
    page.evaluate('window.scrollTo(0,0)')
    page.keyboard.press('Control+Space')
    page.wait_for_timeout(250)
    result['outerAtHeader'] = page.locator('#comment-html-root').evaluate("host => {const t=host.shadowRoot && host.shadowRoot.querySelector('.toolbar');if(!t)return null;const r=t.getBoundingClientRect(),s=getComputedStyle(t),h=host.getBoundingClientRect(),hs=getComputedStyle(host);return {scrollY:scrollY,rootPosition:hs.position,toolbarPosition:s.position,toolbarTop:s.top,toolbarRight:s.right,rect:{x:r.x,y:r.y,width:r.width,height:r.height}}}")
    page.locator('#legacy-kind-ad').scroll_into_view_if_needed()
    page.wait_for_timeout(300)
    result['outerAtCritique'] = page.locator('#comment-html-root').evaluate("host => {const t=host.shadowRoot && host.shadowRoot.querySelector('.toolbar');if(!t)return null;const r=t.getBoundingClientRect(),s=getComputedStyle(t),hs=getComputedStyle(host);return {scrollY:scrollY,rootPosition:hs.position,toolbarPosition:s.position,toolbarTop:s.top,toolbarRight:s.right,rect:{x:r.x,y:r.y,width:r.width,height:r.height},withinViewport:r.top>=0&&r.bottom<=innerHeight&&r.left>=0&&r.right<=innerWidth}}")
    result['blockedNonReadRequests'] = blocked
    (OUT/'live-diagnosis.json').write_text(json.dumps(result, ensure_ascii=False, indent=2))
    page.close()
    context.close()
    browser.close()
print(json.dumps({k:v for k,v in result.items() if k not in ('initial','frames')},ensure_ascii=False,indent=2))
