#!/usr/bin/env python3
"""
GHL OAuth Private App Creator v4
HEADED mode via WSLg display — real GUI browser to bypass reCAPTCHA.
Uses playwright-stealth + persistent profile + human-like interaction.
"""

import json
import time
import re
import sys
import os
from pathlib import Path
from playwright.sync_api import sync_playwright, TimeoutError as PlaywrightTimeout
from playwright_stealth import Stealth

# Configuration
LOGIN_URL = "https://marketplace.gohighlevel.com/login"
MARKETPLACE_URL = "https://marketplace.gohighlevel.com"
EMAIL = "kinan@agileadapt.com"
PASSWORD = "SystemBird505*"
APP_NAME = "Genesis CRM Bridge"
REDIRECT_URI = "https://api.sunaivadigital.com/api/ghl/oauth/callback"
SCREENSHOT_DIR = Path("/mnt/e/genesis-system/GHL/oauth/screenshots")
CREDENTIALS_FILE = Path("/mnt/e/genesis-system/GHL/oauth/app_credentials.json")
BROWSER_PROFILE = "/mnt/e/genesis-system/.browser-data/ghl-marketplace-profile"

REQUIRED_SCOPES = [
    "contacts.readonly", "contacts.write",
    "conversations.readonly", "conversations.write",
    "conversations/message.readonly", "conversations/message.write",
    "calendars.readonly", "calendars.write",
    "calendars/events.readonly", "calendars/events.write",
    "opportunities.readonly", "opportunities.write",
    "locations.readonly", "locations.write",
    "locations/customFields.readonly", "locations/customFields.write",
    "locations/customValues.readonly", "locations/customValues.write",
    "locations/tags.readonly", "locations/tags.write",
    "workflows.readonly",
    "oauth.readonly",
    "oauth.write",
]

step_num = [0]

def ss(page, name):
    step_num[0] += 1
    path = SCREENSHOT_DIR / f"{step_num[0]:02d}_{name}.png"
    page.screenshot(path=str(path), full_page=False)
    print(f"  [SS] {path.name}")
    return path

def human_type(page, text, delay_range=(30, 80)):
    """Type text with random delays to look human."""
    import random
    for char in text:
        page.keyboard.type(char, delay=random.randint(*delay_range))
        time.sleep(random.uniform(0.01, 0.05))

def random_mouse_move(page):
    """Random mouse movements to look human."""
    import random
    for _ in range(3):
        x = random.randint(100, 1800)
        y = random.randint(100, 900)
        page.mouse.move(x, y)
        time.sleep(random.uniform(0.1, 0.3))

def main():
    SCREENSHOT_DIR.mkdir(parents=True, exist_ok=True)
    Path(BROWSER_PROFILE).mkdir(parents=True, exist_ok=True)

    # Check display
    display = os.environ.get("DISPLAY", "")
    print(f"Display: {display}")
    if not display:
        os.environ["DISPLAY"] = ":0"
        print("  Set DISPLAY=:0")

    print("=" * 70)
    print("GHL OAuth App Creator v4 — HEADED via WSLg")
    print("=" * 70)

    with sync_playwright() as p:
        # Launch HEADED browser
        context = p.chromium.launch_persistent_context(
            user_data_dir=BROWSER_PROFILE,
            headless=False,  # HEADED — real GUI window
            args=[
                "--no-sandbox",
                "--disable-blink-features=AutomationControlled",
                "--disable-features=IsolateOrigins,site-per-process",
                "--disable-dev-shm-usage",
                "--start-maximized",
            ],
            viewport={"width": 1920, "height": 1080},
            user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.108 Safari/537.36",
            ignore_https_errors=True,
            locale="en-US",
            timezone_id="Australia/Brisbane",
        )

        page = context.pages[0] if context.pages else context.new_page()
        page.set_default_timeout(30000)

        # Apply stealth
        stealth = Stealth()
        stealth.apply_stealth_sync(page)
        print("  Stealth ACTIVE")

        try:
            # ===== STEP 1: LOGIN =====
            print("\n[STEP 1] Loading login page...")
            page.goto(LOGIN_URL, wait_until="domcontentloaded", timeout=60000)
            page.wait_for_timeout(3000)
            random_mouse_move(page)
            ss(page, "login_loaded")

            # Check if already logged in
            if "login" not in page.url.lower():
                print("  Redirected — may be logged in already")
                page.goto(MARKETPLACE_URL, wait_until="domcontentloaded", timeout=30000)
                page.wait_for_timeout(3000)
                # Check for Sign In link
                try:
                    si = page.locator('a:has-text("Sign In")').first
                    if not si.is_visible(timeout=3000):
                        print("  Already logged in!")
                        # Skip to My Apps
                except:
                    pass

            # Fill login if on login page
            if "login" in page.url.lower():
                print("\n[STEP 2] Filling credentials...")
                page.wait_for_timeout(2000)
                random_mouse_move(page)

                # Click on email field first
                email_input = page.locator('input[placeholder="Enter your email"]').first
                try:
                    if not email_input.is_visible(timeout=5000):
                        email_input = page.locator('input[type="email"]').first
                except:
                    email_input = page.locator('input[type="email"]').first

                email_input.click()
                page.wait_for_timeout(500)
                human_type(page, EMAIL)
                print(f"  Typed email")

                page.wait_for_timeout(500)
                page.keyboard.press("Tab")
                page.wait_for_timeout(500)

                # Password
                pwd_input = page.locator('input[type="password"]').first
                pwd_input.click()
                page.wait_for_timeout(300)
                human_type(page, PASSWORD)
                print(f"  Typed password")

                page.wait_for_timeout(1000)
                random_mouse_move(page)
                ss(page, "creds_filled")

                # Click Sign in button
                print("\n[STEP 3] Clicking Sign in...")
                sign_in_btn = page.locator('button:has-text("Sign in")').first
                sign_in_btn.hover()
                page.wait_for_timeout(500)
                sign_in_btn.click()
                print("  Clicked Sign in")

                # Wait for login response
                print("  Waiting for response (up to 20s)...")

                # Wait for navigation away from login page
                try:
                    page.wait_for_url("**/login**", timeout=3000)
                except:
                    pass

                page.wait_for_timeout(15000)
                ss(page, "after_login")
                print(f"  URL: {page.url}")

                if "login" in page.url.lower():
                    print("\n  *** LOGIN STILL ON LOGIN PAGE ***")
                    # Check for error
                    page_text = page.evaluate("document.body.innerText")
                    if "invalid" in page_text.lower() or "incorrect" in page_text.lower():
                        print("  ERROR: Invalid credentials")
                    elif "captcha" in page_text.lower() or "robot" in page_text.lower():
                        print("  ERROR: CAPTCHA challenge appeared")
                    else:
                        print("  No visible error — might be silent reCAPTCHA block")

                    # Check for reCAPTCHA iframe
                    recaptcha = page.locator('iframe[src*="recaptcha"]').all()
                    if recaptcha:
                        print(f"  Found {len(recaptcha)} reCAPTCHA iframe(s)")

                    ss(page, "login_blocked")

                    # Extract and save the login page state
                    html = page.content()
                    with open(SCREENSHOT_DIR / "login_blocked.html", "w") as f:
                        f.write(html)

                    # CHECK: does the reCAPTCHA need to be solved manually?
                    # Try to find a reCAPTCHA checkbox iframe
                    for frame in page.frames:
                        if "recaptcha" in frame.url:
                            print(f"  reCAPTCHA frame: {frame.url}")
                            # Try clicking the checkbox
                            try:
                                checkbox = frame.locator('.recaptcha-checkbox-border, #recaptcha-anchor').first
                                if checkbox.is_visible(timeout=3000):
                                    checkbox.click()
                                    print("  Clicked reCAPTCHA checkbox!")
                                    page.wait_for_timeout(5000)
                                    # Re-click Sign in
                                    sign_in_btn = page.locator('button:has-text("Sign in")').first
                                    sign_in_btn.click()
                                    page.wait_for_timeout(10000)
                                    ss(page, "after_recaptcha_retry")
                                    print(f"  URL after retry: {page.url}")
                            except Exception as e:
                                print(f"  Could not click reCAPTCHA: {e}")

            # ===== CHECK LOGIN STATUS =====
            print("\n[STEP 4] Checking login status...")
            page.goto(MARKETPLACE_URL, wait_until="domcontentloaded", timeout=30000)
            page.wait_for_timeout(5000)
            ss(page, "marketplace_check")
            print(f"  URL: {page.url}")

            # Look for logged-in indicators
            nav_text = ""
            try:
                header = page.locator('header, nav').first
                if header.is_visible(timeout=3000):
                    nav_text = header.text_content()
                    print(f"  Nav text: {nav_text[:200]}")
            except:
                pass

            logged_in = "Sign In" not in nav_text and ("My Apps" in nav_text or "Account" in nav_text or "Logout" in nav_text)
            print(f"  Logged in: {logged_in}")

            if not logged_in:
                print("\n  *** COLLABORATIVE BROWSER HANDOFF REQUIRED ***")
                print("  reCAPTCHA is blocking automated login.")
                print("  ")
                print("  Kinan: Please do the following:")
                print("  1. Open https://marketplace.gohighlevel.com/login in your browser")
                print("  2. Log in with kinan@agileadapt.com / SystemBird505*")
                print("  3. Tell me when you're logged in")
                print("  4. I'll take over to create the app via the GHL API")
                print("")
                print("  Alternative: I can create a script that works AFTER you")
                print("  manually log in and save cookies.")

                with open(CREDENTIALS_FILE, "w") as f:
                    json.dump({
                        "status": "LOGIN_BLOCKED_RECAPTCHA",
                        "action": "Collaborative Browser Handoff required",
                        "timestamp": time.strftime("%Y-%m-%dT%H:%M:%S"),
                    }, f, indent=2)

                context.close()
                return

            # ====== IF LOGGED IN, CONTINUE WITH APP CREATION ======

            # ===== STEP 5: MY APPS =====
            print("\n[STEP 5] Navigating to My Apps...")
            my_apps = page.locator('a:has-text("My Apps")').first
            try:
                if my_apps.is_visible(timeout=5000):
                    my_apps.click()
                    page.wait_for_timeout(5000)
            except:
                page.goto(f"{MARKETPLACE_URL}/apps", wait_until="domcontentloaded", timeout=30000)
                page.wait_for_timeout(5000)

            ss(page, "my_apps")
            print(f"  URL: {page.url}")

            # ===== STEP 6: CREATE APP =====
            print("\n[STEP 6] Create App...")
            create_btn = page.locator('button:has-text("Create App")').first
            try:
                if create_btn.is_visible(timeout=5000):
                    create_btn.click()
                    page.wait_for_timeout(5000)
            except:
                # Try other patterns
                for txt in ["Create App", "New App", "Add"]:
                    try:
                        btn = page.locator(f'a:has-text("{txt}")').first
                        if btn.is_visible(timeout=2000):
                            btn.click()
                            page.wait_for_timeout(5000)
                            break
                    except:
                        continue

            ss(page, "create_form")
            print(f"  URL: {page.url}")

            # ===== STEP 7: FILL APP DETAILS =====
            print("\n[STEP 7] Filling app details...")

            # App Name
            name_inputs = page.locator('input[type="text"], input:not([type])').all()
            for ni in name_inputs:
                if ni.is_visible():
                    ni.fill(APP_NAME)
                    print(f"  Filled name: {APP_NAME}")
                    break

            page.wait_for_timeout(1000)

            # Private + Agency
            for text in ["Private", "Agency"]:
                for sel_pattern in [f'label:has-text("{text}")', f'div:has-text("{text}") >> visible=true']:
                    try:
                        elem = page.locator(sel_pattern).first
                        if elem.is_visible(timeout=2000):
                            elem.click()
                            print(f"  Selected: {text}")
                            page.wait_for_timeout(500)
                            break
                    except:
                        continue

            ss(page, "details_filled")

            # ===== STEP 8: REDIRECT URI =====
            print("\n[STEP 8] Redirect URI...")
            redir_input = page.locator('input[placeholder*="redirect" i], input[placeholder*="URI" i], input[type="url"]').first
            try:
                if redir_input.is_visible(timeout=5000):
                    redir_input.fill(REDIRECT_URI)
                    print(f"  Set: {REDIRECT_URI}")
            except:
                print("  Redirect URI field not found yet")

            ss(page, "redirect_uri")

            # ===== STEP 9: SCOPES =====
            print("\n[STEP 9] Selecting scopes...")

            # Try finding scopes tab/section
            for tab in ["Scopes", "Permissions"]:
                try:
                    t = page.locator(f'button:has-text("{tab}")').first
                    if t.is_visible(timeout=2000):
                        t.click()
                        page.wait_for_timeout(2000)
                        break
                except:
                    continue

            selected = 0
            missing = []
            for scope in REQUIRED_SCOPES:
                found = False
                for sel in [f'input[value="{scope}"]', f'label:has-text("{scope}")']:
                    try:
                        elem = page.locator(sel).first
                        if elem.is_visible(timeout=500):
                            tag = elem.evaluate("el => el.tagName")
                            if tag == "INPUT":
                                if not elem.is_checked():
                                    elem.check()
                            else:
                                elem.click()
                            found = True
                            selected += 1
                            break
                    except:
                        continue
                if not found:
                    missing.append(scope)
                page.wait_for_timeout(100)

            print(f"  Selected: {selected}/{len(REQUIRED_SCOPES)}")
            ss(page, "scopes")

            # ===== STEP 10: SAVE =====
            print("\n[STEP 10] Saving...")
            for txt in ["Save", "Create", "Submit"]:
                try:
                    btn = page.locator(f'button:has-text("{txt}")').first
                    if btn.is_visible(timeout=2000):
                        btn.click()
                        page.wait_for_timeout(8000)
                        break
                except:
                    continue

            ss(page, "saved")
            print(f"  URL: {page.url}")

            # ===== STEP 11: CAPTURE CREDENTIALS =====
            print("\n[STEP 11] Capturing credentials...")
            page_text = page.evaluate("document.body.innerText")

            client_id = None
            client_secret = None

            # Regex search
            id_match = re.search(r'Client\s*ID[:\s]*([a-f0-9-]{20,})', page_text, re.I)
            if id_match:
                client_id = id_match.group(1)

            secret_match = re.search(r'Client\s*Secret[:\s]*([a-zA-Z0-9_-]{20,})', page_text, re.I)
            if secret_match:
                client_secret = secret_match.group(1)

            # Try input fields
            all_inputs = page.locator('input:visible').all()
            for inp in all_inputs:
                try:
                    val = inp.input_value()
                    name = inp.get_attribute("name") or ""
                    if "client" in name.lower() and "id" in name.lower():
                        client_id = val
                    elif "client" in name.lower() and "secret" in name.lower():
                        client_secret = val
                except:
                    pass

            ss(page, "credentials_captured")

            creds = {
                "app_name": APP_NAME,
                "client_id": client_id,
                "client_secret": client_secret,
                "redirect_uri": REDIRECT_URI,
                "scopes_selected": selected,
                "scopes_missing": missing,
                "created_at": time.strftime("%Y-%m-%dT%H:%M:%S"),
                "page_url": page.url,
                "page_text_excerpt": page_text[:3000],
            }
            with open(CREDENTIALS_FILE, "w") as f:
                json.dump(creds, f, indent=2)

            print(f"\n{'='*70}")
            print("RESULT")
            print(f"{'='*70}")
            print(f"  Client ID:     {client_id or 'NOT CAPTURED'}")
            print(f"  Client Secret: {client_secret or 'NOT CAPTURED'}")
            print(f"  Scopes:        {selected}/{len(REQUIRED_SCOPES)}")
            print(f"  Saved to:      {CREDENTIALS_FILE}")

        except Exception as e:
            print(f"\nFATAL: {e}")
            import traceback
            traceback.print_exc()
            ss(page, "FATAL")
        finally:
            context.close()


if __name__ == "__main__":
    main()
