#!/usr/bin/env python3
"""
NotebookLM login — handles 2FA + passkey speedbump inline.
"""
import asyncio, json, time, sys
from pathlib import Path
from playwright.async_api import async_playwright

EMAIL = "moon.clawdbot@gmail.com"
PASSWORD = "Ai210126"
PROFILE_DIR = Path.home() / ".notebooklm" / "browser_profile"
STORAGE_PATH = Path.home() / ".notebooklm" / "storage_state.json"
SIGNAL_FILE = Path("/tmp/nlm_2fa_ready")
CODE_FILE   = Path("/tmp/nlm_2fa_code")

SIGNAL_FILE.unlink(missing_ok=True)
CODE_FILE.unlink(missing_ok=True)

def wait_for_code(timeout=600):
    SIGNAL_FILE.write_text("waiting")
    print("SIGNAL_WRITTEN", flush=True)
    start = time.time()
    while time.time() - start < timeout:
        if CODE_FILE.exists():
            code = CODE_FILE.read_text().strip()
            CODE_FILE.unlink(missing_ok=True)
            SIGNAL_FILE.unlink(missing_ok=True)
            return code
        time.sleep(1)
    raise TimeoutError("No 2FA code in 10 minutes")

async def fill_field(page, selectors, value):
    for sel in selectors:
        try:
            el = page.locator(sel).first
            if await el.count() > 0:
                await el.click()
                await page.wait_for_timeout(300)
                await el.fill(value)
                print(f"  Filled [{sel}]", flush=True)
                return True
        except Exception:
            continue
    return False

async def dismiss_interstitial(page):
    """Click through any Google interstitials (passkey, privacy, etc.)."""
    url = page.url
    print(f"  Interstitial URL: {url[:80]}", flush=True)
    
    # Try button text matches
    for text in ["Not now", "Skip", "No thanks", "Maybe later", "Continue", "Done", "Dismiss", "Not now, thanks"]:
        try:
            btn = page.get_by_role("button", name=text, exact=False)
            if await btn.count() > 0:
                await btn.first.click()
                print(f"  Clicked button: '{text}'", flush=True)
                await page.wait_for_timeout(3000)
                return True
        except Exception:
            pass
    
    # Try link text
    for text in ["Not now", "Skip", "No thanks", "Maybe later"]:
        try:
            link = page.get_by_role("link", name=text, exact=False)
            if await link.count() > 0:
                await link.first.click()
                print(f"  Clicked link: '{text}'", flush=True)
                await page.wait_for_timeout(3000)
                return True
        except Exception:
            pass

    # Press Escape
    await page.keyboard.press("Escape")
    await page.wait_for_timeout(2000)
    return False

async def main():
    PROFILE_DIR.mkdir(parents=True, exist_ok=True)

    async with async_playwright() as p:
        ctx = await p.chromium.launch_persistent_context(
            str(PROFILE_DIR),
            channel="chrome",
            headless=False,
            slow_mo=100,
            args=["--start-maximized", "--disable-blink-features=AutomationControlled"],
            ignore_default_args=["--enable-automation"],
        )
        page = ctx.pages[0] if ctx.pages else await ctx.new_page()

        print("-> Navigating to NotebookLM...", flush=True)
        await page.goto("https://notebooklm.google.com", wait_until="domcontentloaded")
        await page.wait_for_timeout(4000)
        print(f"   URL: {page.url}", flush=True)

        if "notebooklm.google.com" in page.url and "accounts.google.com" not in page.url:
            print("ALREADY_LOGGED_IN", flush=True)
        else:
            # Email
            print("-> Entering email...", flush=True)
            await fill_field(page, ['input[type="email"]'], EMAIL)
            await page.keyboard.press("Enter")
            await page.wait_for_timeout(4000)

            # Password
            print("-> Entering password...", flush=True)
            await fill_field(page, ['input[type="password"]'], PASSWORD)
            await page.keyboard.press("Enter")
            await page.wait_for_timeout(5000)
            print(f"   URL: {page.url}", flush=True)

            # 2FA
            if any(x in page.url for x in ["challenge", "ipp", "2sv"]):
                print("2FA_REQUIRED", flush=True)
                loop = asyncio.get_event_loop()
                code = await loop.run_in_executor(None, wait_for_code, 600)
                print(f"GOT_CODE {code}", flush=True)

                filled = await fill_field(page, [
                    'input[type="tel"]',
                    'input[name="totpPin"]',
                    '#totpPin',
                    'input[data-initial-value]',
                    'input[autocomplete="one-time-code"]',
                    'input.whsOnd',
                ], code)
                if not filled:
                    await page.keyboard.type(code)

                await page.keyboard.press("Enter")
                await page.wait_for_timeout(6000)
                print(f"   URL after 2FA: {page.url}", flush=True)

            # Handle post-login interstitials in a loop
            for attempt in range(8):
                url = page.url
                if "notebooklm.google.com" in url and "accounts.google.com" not in url:
                    break
                if "accounts.google.com" not in url:
                    break
                print(f"-> Interstitial #{attempt+1}, dismissing...", flush=True)
                await dismiss_interstitial(page)
                await page.wait_for_timeout(2000)
                print(f"   URL: {page.url}", flush=True)
            
            # If still on Google, force navigate
            if "accounts.google.com" in page.url:
                print("-> Force-navigating to NotebookLM...", flush=True)
                await page.goto("https://notebooklm.google.com", wait_until="domcontentloaded")
                await page.wait_for_timeout(8000)
                print(f"   URL: {page.url}", flush=True)

        # Final check
        final_url = page.url
        print(f"-> Final URL: {final_url}", flush=True)

        if "accounts.google.com" in final_url and "notebooklm" not in final_url:
            print("FAIL: Not authenticated", flush=True)
            await ctx.close()
            sys.exit(1)

        # Save state
        print("-> Saving storage state...", flush=True)
        await ctx.storage_state(path=str(STORAGE_PATH))
        await ctx.close()

        state = json.loads(STORAGE_PATH.read_text())
        cookies = state.get("cookies", [])
        names = [f"{c['name']}@{c['domain']}" for c in cookies]
        print(f"   {len(cookies)} cookies: {names}", flush=True)

        has_sid  = any(c["name"] == "SID" for c in cookies)
        has_psid = any("PSID" in c["name"] for c in cookies)
        print(f"SID: {has_sid} | PSID: {has_psid}", flush=True)
        print("SUCCESS" if (has_sid or has_psid) else "WARNING: SID missing", flush=True)

if __name__ == "__main__":
    asyncio.run(main())
