#!/usr/bin/env python3
"""Six Senses deep DOM extractor -- SPA-aware, Firefox headless."""
import json, time
from pathlib import Path
from playwright.sync_api import sync_playwright

OUT = Path("/home/sirdrez/arisingmedia-websites/bigbreath.co/.planning/ref-patterns/sixsenses")
OUT.mkdir(parents=True, exist_ok=True)

UA = "Mozilla/5.0 (X11; Linux x86_64; rv:124.0) Gecko/20100101 Firefox/124.0"

PAGES = [
    ("homepage", "https://www.sixsenses.com/en/"),
    ("resorts", "https://www.sixsenses.com/en/resorts"),
    ("wellness", "https://www.sixsenses.com/en/wellness"),
]

COOKIE_SELECTORS = [
    "button:has-text('Accept All')",
    "button:has-text('Accept')",
    "[id*='onetrust-accept']",
    "button:has-text('I Accept')",
    "button:has-text('Agree')",
    "[class*='accept']",
    "[class*='consent'] button",
]

EXTRACT_JS = """
() => {
    const results = [];
    // Cast widest possible net for structural containers
    const candidates = document.querySelectorAll(
        'section, article, main, [class*="section"], [class*="block"], [class*="hero"], ' +
        '[class*="module"], [class*="container"], [class*="panel"], [class*="row"], ' +
        '[class*="strip"], [class*="band"], [class*="segment"], [class*="wrapper"], ' +
        '[class*="carousel"], [class*="slider"], [class*="grid"], [class*="layout"]'
    );

    const seen = new Set();
    const minH = 80;

    for (const el of candidates) {
        const rect = el.getBoundingClientRect();
        const scrollH = el.scrollHeight;
        const h = Math.max(rect.height, scrollH);
        if (h < minH) continue;
        // skip tiny or hidden
        if (rect.width < 200) continue;

        const cls = (el.className || '').toString().slice(0, 150);
        const tag = el.tagName.toLowerCase();
        const key = tag + '|' + cls.slice(0, 60);
        if (seen.has(key)) continue;
        seen.add(key);

        const st = getComputedStyle(el);
        const bg = st.backgroundColor;
        const pt = st.paddingTop;
        const pb = st.paddingBottom;
        const color = st.color;
        const fontSize = st.fontSize;

        const txt = (el.innerText || '').slice(0, 500).replace(/\\n/g, ' ').trim();
        const cardCount = el.querySelectorAll('[class*="card"],[class*="item"],[class*="tile"],article,li[class]').length;
        const hasVideo = !!el.querySelector('video,[class*="video"],iframe[src*="vimeo"],iframe[src*="youtube"]');
        const imgCount = el.querySelectorAll('img,picture,[class*="image"]').length;
        const hasBtn = !!el.querySelector('a[class*="btn"],button,[class*="cta"],[class*="button"]');

        // eyebrow / labels
        const eyebrows = [];
        for (const small of el.querySelectorAll('[class*="eyebrow"],[class*="label"],[class*="tag"],[class*="category"],[class*="kicker"],small')) {
            const t = (small.innerText || '').trim();
            if (t && t.length < 60) eyebrows.push(t);
        }

        // headings
        const headings = [];
        for (const hx of el.querySelectorAll('h1,h2,h3')) {
            const t = (hx.innerText || '').trim();
            if (t && t.length < 120) headings.push({tag: hx.tagName.toLowerCase(), text: t});
            if (headings.length >= 3) break;
        }

        // CTA text
        const ctas = [];
        for (const a of el.querySelectorAll('a[class*="btn"],a[class*="cta"],a[class*="button"],button')) {
            const t = (a.innerText || '').trim();
            if (t && t.length < 60) ctas.push(t);
            if (ctas.length >= 3) break;
        }

        results.push({
            tag, cls, bg, pt, pb, color, fontSize,
            width_px: Math.round(rect.width || document.body.scrollWidth),
            height_px: Math.round(h),
            card_count: cardCount,
            has_video: hasVideo,
            img_count: imgCount,
            has_btn: hasBtn,
            eyebrows,
            headings,
            ctas,
            text_snippet: txt.slice(0, 300),
        });

        if (results.length >= 60) break;
    }
    return results;
}
"""

PAGE_META_JS = """
() => {
    const title = document.title;
    const fonts = [...new Set([...document.querySelectorAll('*')].slice(0,200).map(el => getComputedStyle(el).fontFamily))].slice(0,6);
    const colors = [...new Set([...document.querySelectorAll('a,button,[class*="btn"],[class*="cta"]')].slice(0,20).map(el => getComputedStyle(el).backgroundColor))].filter(c => c && c !== 'rgba(0, 0, 0, 0)').slice(0,5);
    return {title, fonts, brand_colors: colors};
}
"""

def dismiss_cookies(page):
    for sel in COOKIE_SELECTORS:
        try:
            btn = page.locator(sel).first
            if btn.is_visible(timeout=2000):
                btn.click()
                page.wait_for_timeout(1000)
                return
        except Exception:
            pass

def scroll_page(page):
    # scroll down to trigger lazy loads
    page.evaluate("window.scrollTo(0, document.body.scrollHeight / 3)")
    page.wait_for_timeout(800)
    page.evaluate("window.scrollTo(0, document.body.scrollHeight * 2 / 3)")
    page.wait_for_timeout(800)
    page.evaluate("window.scrollTo(0, document.body.scrollHeight)")
    page.wait_for_timeout(1000)
    page.evaluate("window.scrollTo(0, 0)")
    page.wait_for_timeout(500)

def load_page(ctx, url):
    page = ctx.new_page()
    resp = None
    try:
        resp = page.goto(url, wait_until="domcontentloaded", timeout=60000)
        page.wait_for_timeout(4000)
        dismiss_cookies(page)
        page.wait_for_timeout(1500)
        try:
            page.wait_for_load_state("networkidle", timeout=20000)
        except Exception:
            pass
        page.wait_for_timeout(2000)
        scroll_page(page)
        page.wait_for_timeout(1500)
    except Exception as e:
        return page, resp, str(e)
    return page, resp, None

def run():
    structure = {}
    screenshots = []

    with sync_playwright() as p:
        browser = p.firefox.launch(headless=True)
        ctx = browser.new_context(
            viewport={"width": 1440, "height": 900},
            user_agent=UA,
        )
        ctx.set_extra_http_headers({"Accept-Language": "en-US,en;q=0.9"})

        for slug, url in PAGES:
            print(f"\n[{slug}] {url}")
            page, resp, err = load_page(ctx, url)

            shot = OUT / f"{slug}.png"
            try:
                page.screenshot(path=str(shot), full_page=True, timeout=40000)
                screenshots.append(str(shot))
                sz = shot.stat().st_size
                print(f"  screenshot: {sz:,} bytes")
            except Exception as e:
                print(f"  screenshot failed: {e}")

            sections = []
            meta = {}
            if not err:
                try:
                    sections = page.evaluate(EXTRACT_JS)
                    meta = page.evaluate(PAGE_META_JS)
                    print(f"  sections: {len(sections)}")
                except Exception as e:
                    print(f"  extract error: {e}")

            # resort detail follow
            if slug == "resorts" and not err:
                links = page.query_selector_all("a[href*='/resorts/']")
                resort_url = None
                for lnk in links:
                    href = lnk.get_attribute("href") or ""
                    if "/resorts/" in href and href != "/en/resorts" and "/resorts" != href.rstrip("/"):
                        resort_url = href if href.startswith("http") else f"https://www.sixsenses.com{href}"
                        break
                if resort_url:
                    print(f"  following resort: {resort_url}")
                    rpage, rresp, rerr = load_page(ctx, resort_url)
                    rshot = OUT / "resort_detail.png"
                    try:
                        rpage.screenshot(path=str(rshot), full_page=True, timeout=40000)
                        screenshots.append(str(rshot))
                        print(f"  resort screenshot: {rshot.stat().st_size:,} bytes")
                    except Exception as e:
                        print(f"  resort screenshot failed: {e}")
                    rsecs = []
                    rmeta = {}
                    if not rerr:
                        try:
                            rsecs = rpage.evaluate(EXTRACT_JS)
                            rmeta = rpage.evaluate(PAGE_META_JS)
                            print(f"  resort sections: {len(rsecs)}")
                        except Exception as e:
                            print(f"  resort extract error: {e}")
                    structure["resort_detail"] = {
                        "url": resort_url, "meta": rmeta,
                        "section_count": len(rsecs), "sections": rsecs,
                        "error": rerr,
                    }
                    rpage.close()

            structure[slug] = {
                "url": url, "final_url": page.url,
                "http_status": resp.status if resp else None,
                "meta": meta,
                "section_count": len(sections),
                "sections": sections,
                "error": err,
            }
            page.close()

        browser.close()

    out_json = OUT / "structure.json"
    out_json.write_text(json.dumps(structure, indent=2))
    print(f"\nstructure.json: {out_json.stat().st_size:,} bytes")
    print(f"Screenshots: {len(screenshots)}")
    return structure, screenshots

if __name__ == "__main__":
    s, shots = run()
    total_secs = sum(v.get("section_count", 0) for v in s.values())
    print(f"Total sections across all pages: {total_secs}")
