"""
VentraIP DNS Config — V2 (UI Navigation)
==========================================
Navigates through VIPcontrol dashboard UI to configure DNS.
Instead of direct URLs (which 404), clicks DNS buttons in the domain list.

Usage:
    python3 ventraip_v2.py                  # Login + explore first domain DNS page
    python3 ventraip_v2.py --configure      # Login + configure all domains
    python3 ventraip_v2.py --code 123456    # Pre-provide 2FA code
"""

import argparse
import json
import re
import sys
import time
from pathlib import Path
from playwright.sync_api import sync_playwright
from playwright_stealth import Stealth

VENTRAIP_EMAIL = "kinan@protonmail.com"
VENTRAIP_PASSWORD = "9iphQKcIv0#2J0Ce"
NETLIFY_A_RECORD = "75.2.60.5"

MANIFEST_PATH = "/mnt/e/genesis-system/scripts/gold_pipeline/output/deployment_manifest.json"
SCREENSHOT_DIR = Path("/mnt/e/genesis-system/scripts/gold_pipeline/output/ventraip_screenshots")
OUTPUT_DIR = Path("/mnt/e/genesis-system/scripts/gold_pipeline/output")
CODE_FILE = OUTPUT_DIR / "ventraip_2fa_code.txt"

SCREENSHOT_DIR.mkdir(parents=True, exist_ok=True)

VENTRAIP_DOMAINS = [
    "sydneychatbots.com.au", "brisbanechatbots.com.au", "melbournechatbots.com.au",
    "adelaidechatbots.com.au", "cairnschatbots.com.au", "sunshinecoastchatbots.com.au",
    "townsvillechatbots.com.au", "darwinchatbots.com.au", "aichatbotsbrisbane.au",
    "aichatbotsaustralia.au",
    "tradiechatbots.com.au", "tradiechatbot.com.au", "tradiesvoice.com.au",
    "tradieautomation.com.au", "aitradie.au", "sparkybots.com.au", "plumberbots.com.au",
    "hvacbots.com.au", "electricianbotai.au", "solarbotai.au", "mechanicbot.au",
    "locksmithbot.au", "rooferbot.au",
    "receptionistai.au", "beautybot.com.au", "propertybotai.com.au", "propertybotai.au",
    "dentalbotai.au", "clinicaibot.au", "lawyerbot.au", "legalbotai.au", "rentbot.au",
    "voiceassistant.com.au", "voiceassistant.au", "aivoicereceptionist.au",
    "phonebot.au", "talkbot.au", "bookingbot.au",
]


def get_domain_map():
    with open(MANIFEST_PATH) as f:
        manifest = json.load(f)
    result = {}
    for domain in VENTRAIP_DOMAINS:
        if domain in manifest:
            match = re.search(r"https://([^.]+)\.netlify\.app", manifest[domain])
            if match:
                result[domain] = match.group(1)
    return result


def wait_for_code(timeout_secs=300) -> str:
    """Poll CODE_FILE for the 2FA code."""
    if CODE_FILE.exists():
        CODE_FILE.unlink()

    print(f"WAITING_FOR_CODE:{CODE_FILE}")
    sys.stdout.flush()

    start = time.time()
    while time.time() - start < timeout_secs:
        if CODE_FILE.exists():
            code = CODE_FILE.read_text().strip()
            if code:
                CODE_FILE.unlink()
                return code
        time.sleep(0.5)

    return ""


def login(page, code=None):
    """Login to VIPcontrol with stealth + 2FA handling. Returns True on success."""
    print("[LOGIN] Navigating to VIPcontrol (stealth mode)...")
    sys.stdout.flush()
    page.goto("https://vip.ventraip.com.au/login/", timeout=60000)
    page.wait_for_timeout(3000)

    # Human-like mouse movements
    page.mouse.move(500, 400)
    page.wait_for_timeout(500)
    page.mouse.move(800, 300)
    page.wait_for_timeout(300)

    # Fill credentials
    email_input = page.query_selector('input[name="email"], input[type="email"]')
    if email_input:
        email_input.click()
        page.wait_for_timeout(200)
        email_input.type(VENTRAIP_EMAIL, delay=50)

    page.wait_for_timeout(300)

    pass_input = page.query_selector('input[name="password"], input[type="password"]')
    if pass_input:
        pass_input.click()
        page.wait_for_timeout(200)
        pass_input.type(VENTRAIP_PASSWORD, delay=30)

    page.wait_for_timeout(500)

    # Click login
    btn = page.query_selector('button:has-text("Login")') or page.query_selector('button[type="submit"]')
    if btn:
        btn.hover()
        page.wait_for_timeout(200)
        btn.click()

    print("[LOGIN] Waiting for 2FA page...")
    sys.stdout.flush()
    page.wait_for_timeout(6000)

    content = page.content()

    if "two-factor" in content.lower() or "authentication" in content.lower() or "verify" in content.lower():
        print("[2FA] Code required. Check kinan@protonmail.com")
        sys.stdout.flush()

        if not code:
            code = wait_for_code(timeout_secs=300)

        if not code:
            print("[2FA] No code received within timeout")
            sys.stdout.flush()
            return False

        print(f"[2FA] Entering code: {code}")
        sys.stdout.flush()

        # Find code input
        code_input = (
            page.query_selector('input[placeholder*="Authentication"]')
            or page.query_selector('input[placeholder*="Code"]')
            or page.query_selector('input[placeholder*="code"]')
            or page.query_selector('input[name*="code"]')
            or page.query_selector('input[name*="token"]')
        )
        if not code_input:
            inputs = page.query_selector_all('input[type="text"], input[type="number"], input:not([type])')
            for inp in inputs:
                if inp.is_visible():
                    code_input = inp
                    break

        if code_input:
            code_input.click()
            page.wait_for_timeout(300)
            code_input.type(code, delay=80)
            page.wait_for_timeout(800)

            verify_btn = (
                page.query_selector('button:has-text("Verify")')
                or page.query_selector('button:has-text("Login")')
                or page.query_selector('button[type="submit"]')
            )
            if verify_btn:
                verify_btn.hover()
                page.wait_for_timeout(300)
                verify_btn.click()

            page.wait_for_timeout(10000)
            page.screenshot(path=str(SCREENSHOT_DIR / "v2_after_2fa.png"))

            url = page.url
            print(f"[2FA] URL after verify: {url}")
            sys.stdout.flush()

            if "login" in url.lower() and "dashboard" not in url.lower():
                print("[2FA] FAILED - still on login page")
                sys.stdout.flush()
                return False

            print("[2FA] LOGIN SUCCESSFUL!")
            sys.stdout.flush()
            return True
        else:
            print("[2FA] Could not find code input")
            sys.stdout.flush()
            return False

    elif "login" not in page.url.lower():
        print("[LOGIN] Already authenticated!")
        sys.stdout.flush()
        return True
    else:
        print("[LOGIN] Unexpected state")
        sys.stdout.flush()
        page.screenshot(path=str(SCREENSHOT_DIR / "v2_unexpected.png"))
        return False


def go_to_dashboard(page):
    """Navigate to dashboard and expand all domains."""
    page.goto("https://vip.ventraip.com.au/", timeout=30000)
    page.wait_for_timeout(3000)

    # Click "SHOW ALL DOMAINS" to expand the full list
    show_all = page.query_selector('a:has-text("SHOW ALL DOMAINS")') or page.query_selector('button:has-text("SHOW ALL")')
    if show_all:
        show_all.click()
        page.wait_for_timeout(3000)
        print("[DASHBOARD] Expanded all domains")
        sys.stdout.flush()
    else:
        print("[DASHBOARD] 'SHOW ALL DOMAINS' not found, may already be expanded")
        sys.stdout.flush()

    page.screenshot(path=str(SCREENSHOT_DIR / "v2_dashboard_expanded.png"))


def click_dns_for_domain(page, domain):
    """Find a domain's row in the dashboard and click its DNS button.
    Returns True if navigation succeeded."""

    # Look for the domain text in the page, then find its DNS button
    # Strategy: find all rows, match domain text, click DNS in that row

    # First try: find an element containing the domain text
    domain_el = page.query_selector(f'text="{domain}"')
    if not domain_el:
        # Try partial match
        domain_el = page.query_selector(f'td:has-text("{domain}")') or page.query_selector(f'div:has-text("{domain}")')

    if domain_el:
        # Get the parent row
        row = domain_el.evaluate_handle("""el => {
            // Walk up to find the row container
            let current = el;
            for (let i = 0; i < 10; i++) {
                current = current.parentElement;
                if (!current) break;
                // Check if this is a table row or a div that contains DNS button
                if (current.tagName === 'TR' ||
                    (current.querySelector && current.querySelector('button, a'))) {
                    // Check if it has a DNS button/link
                    const dnsBtn = current.querySelector('a[href*="dns"], button:has-text("DNS"), a:has-text("DNS")');
                    if (dnsBtn) return current;
                }
            }
            return null;
        }""")

        if row:
            # Find and click the DNS button within this row
            dns_btn = row.as_element().query_selector('button:has-text("DNS")') or row.as_element().query_selector('a:has-text("DNS")')
            if dns_btn:
                # Get href if it's a link
                href = dns_btn.get_attribute("href")
                if href:
                    print(f"  [DNS] Found DNS link: {href}")
                    sys.stdout.flush()
                    # Navigate directly to the href
                    if href.startswith("/"):
                        page.goto(f"https://vip.ventraip.com.au{href}", timeout=30000)
                    else:
                        page.goto(href, timeout=30000)
                else:
                    dns_btn.click()
                page.wait_for_timeout(3000)
                return True

    # Fallback: try to find DNS buttons/links with domain in href
    all_dns_links = page.query_selector_all('a:has-text("DNS"), button:has-text("DNS")')
    for link in all_dns_links:
        href = link.get_attribute("href") or ""
        # Check if the link's row mentions our domain
        parent_text = link.evaluate("el => el.closest('tr, [class*=row], [class*=domain]')?.textContent || ''")
        if domain in parent_text:
            print(f"  [DNS] Found via parent text match, href={href[:80]}")
            sys.stdout.flush()
            if href and href.startswith("/"):
                page.goto(f"https://vip.ventraip.com.au{href}", timeout=30000)
            elif href:
                page.goto(href, timeout=30000)
            else:
                link.click()
            page.wait_for_timeout(3000)
            return True

    # Last resort: try XPath to find DNS button near domain text
    try:
        # Use page.locator for more flexible matching
        row_locator = page.locator(f'tr:has-text("{domain}"), div.domain-row:has-text("{domain}"), [class*="row"]:has-text("{domain}")')
        if row_locator.count() > 0:
            dns_in_row = row_locator.first.locator('text="DNS"')
            if dns_in_row.count() > 0:
                dns_in_row.first.click()
                page.wait_for_timeout(3000)
                return True
    except Exception as e:
        print(f"  [DNS] Locator fallback error: {e}")
        sys.stdout.flush()

    return False


def explore_dns_page(page, domain):
    """Take detailed screenshots and HTML dump of a DNS page for analysis."""
    safe = domain.replace(".", "_")
    page.screenshot(path=str(SCREENSHOT_DIR / f"v2_dns_{safe}.png"))

    # Save page HTML for analysis
    html = page.content()
    html_path = SCREENSHOT_DIR / f"v2_dns_{safe}.html"
    html_path.write_text(html[:200000], encoding="utf-8")

    print(f"  [EXPLORE] URL: {page.url}")
    print(f"  [EXPLORE] HTML saved: {html_path}")
    sys.stdout.flush()

    # Look for Add Record button
    add_btn = (
        page.query_selector('button:has-text("Add Record")')
        or page.query_selector('button:has-text("Add DNS")')
        or page.query_selector('a:has-text("Add Record")')
        or page.query_selector('button:has-text("Add")')
    )
    if add_btn:
        print("  [EXPLORE] Found 'Add Record' button!")
    else:
        print("  [EXPLORE] No 'Add Record' button found")

    # Look for existing records
    records = page.query_selector_all('tr, [class*="record"]')
    print(f"  [EXPLORE] Found {len(records)} potential record elements")
    sys.stdout.flush()


def configure_dns(page, domain, netlify_sub):
    """Add A and CNAME records on the DNS management page."""
    netlify_target = f"{netlify_sub}.netlify.app"
    result = {"domain": domain, "netlify": netlify_target, "status": "unknown", "a_record": False, "cname_record": False}

    safe = domain.replace(".", "_")
    page.screenshot(path=str(SCREENSHOT_DIR / f"v2_dns_{safe}_before.png"))

    # Check we're on a DNS page
    content = page.content().lower()
    url = page.url.lower()
    if "dns" not in url and "record" not in content and "zone" not in content:
        result["status"] = "not_dns_page"
        print(f"  [DNS] Not on DNS page. URL: {page.url}")
        sys.stdout.flush()
        return result

    # === ADD A RECORD ===
    add_btn = (
        page.query_selector('button:has-text("Add Record")')
        or page.query_selector('button:has-text("Add DNS Record")')
        or page.query_selector('a:has-text("Add Record")')
        or page.query_selector('button:has-text("Add")')
    )

    if not add_btn:
        result["status"] = "no_add_button"
        print(f"  [DNS] No 'Add Record' button found")
        sys.stdout.flush()
        page.screenshot(path=str(SCREENSHOT_DIR / f"v2_dns_{safe}_no_add.png"))
        return result

    # Click Add Record
    add_btn.click()
    page.wait_for_timeout(2000)
    page.screenshot(path=str(SCREENSHOT_DIR / f"v2_dns_{safe}_add_form.png"))

    # Select record type = A
    type_sel = page.query_selector('select[name*="type"], select[name*="record"], select[id*="type"]')
    if type_sel:
        type_sel.select_option(label="A")
        page.wait_for_timeout(500)
    else:
        # Try clicking a type option in a dropdown/radio
        a_option = page.query_selector('option[value="A"], input[value="A"], label:has-text("A Record")')
        if a_option:
            a_option.click()
            page.wait_for_timeout(500)

    # Fill hostname = @
    name_inp = page.query_selector('input[name*="name"], input[name*="host"], input[placeholder*="Name"], input[placeholder*="Host"], input[placeholder*="name"]')
    if name_inp:
        name_inp.fill("")
        name_inp.type("@", delay=50)

    # Fill value = Netlify A record IP
    val_inp = page.query_selector('input[name*="content"], input[name*="value"], input[name*="address"], input[name*="data"], input[name*="target"], input[placeholder*="Content"], input[placeholder*="Value"], input[placeholder*="Address"], input[placeholder*="IP"]')
    if val_inp:
        val_inp.fill("")
        val_inp.type(NETLIFY_A_RECORD, delay=30)

    page.wait_for_timeout(500)
    page.screenshot(path=str(SCREENSHOT_DIR / f"v2_dns_{safe}_a_filled.png"))

    # Save
    save_btn = (
        page.query_selector('button:has-text("Save")')
        or page.query_selector('button:has-text("Add Record")')
        or page.query_selector('button:has-text("Add")')
        or page.query_selector('button:has-text("Create")')
        or page.query_selector('button[type="submit"]')
    )
    if save_btn:
        save_btn.click()
        page.wait_for_timeout(3000)
        result["a_record"] = True
        print(f"  [DNS] A record saved")
        sys.stdout.flush()

    # === ADD CNAME RECORD ===
    page.wait_for_timeout(1000)

    add_btn2 = (
        page.query_selector('button:has-text("Add Record")')
        or page.query_selector('button:has-text("Add DNS Record")')
        or page.query_selector('a:has-text("Add Record")')
        or page.query_selector('button:has-text("Add")')
    )
    if add_btn2:
        add_btn2.click()
        page.wait_for_timeout(2000)

    type_sel2 = page.query_selector('select[name*="type"], select[name*="record"], select[id*="type"]')
    if type_sel2:
        type_sel2.select_option(label="CNAME")
        page.wait_for_timeout(500)

    name_inp2 = page.query_selector('input[name*="name"], input[name*="host"], input[placeholder*="Name"], input[placeholder*="Host"]')
    if name_inp2:
        name_inp2.fill("")
        name_inp2.type("www", delay=50)

    val_inp2 = page.query_selector('input[name*="content"], input[name*="value"], input[name*="target"], input[name*="data"], input[placeholder*="Content"], input[placeholder*="Value"], input[placeholder*="Target"]')
    if val_inp2:
        val_inp2.fill("")
        val_inp2.type(netlify_target, delay=20)

    page.wait_for_timeout(500)

    save_btn2 = (
        page.query_selector('button:has-text("Save")')
        or page.query_selector('button:has-text("Add Record")')
        or page.query_selector('button:has-text("Add")')
        or page.query_selector('button:has-text("Create")')
        or page.query_selector('button[type="submit"]')
    )
    if save_btn2:
        save_btn2.click()
        page.wait_for_timeout(3000)
        result["cname_record"] = True
        print(f"  [DNS] CNAME record saved")
        sys.stdout.flush()

    result["status"] = "configured" if (result["a_record"] and result["cname_record"]) else "partial"
    page.screenshot(path=str(SCREENSHOT_DIR / f"v2_dns_{safe}_after.png"))
    return result


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("--configure", action="store_true")
    parser.add_argument("--domain", help="Single domain to configure")
    parser.add_argument("--code", help="Pre-provide 2FA code")
    args = parser.parse_args()

    domain_map = get_domain_map()
    print(f"[INIT] {len(domain_map)} domains in manifest")
    sys.stdout.flush()

    with sync_playwright() as pw:
        browser = pw.chromium.launch(
            headless=True,
            args=[
                "--no-sandbox",
                "--disable-blink-features=AutomationControlled",
                "--disable-features=IsolateOrigins,site-per-process",
                "--disable-site-isolation-trials",
            ],
        )
        context = browser.new_context(
            user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
            viewport={"width": 1920, "height": 1080},
            locale="en-AU",
            timezone_id="Australia/Brisbane",
            color_scheme="light",
        )

        page = context.new_page()

        # Apply stealth
        stealth = Stealth()
        stealth.apply_stealth_sync(page)

        page.add_init_script("""
            Object.defineProperty(navigator, 'webdriver', { get: () => undefined });
            window.chrome = { runtime: {}, loadTimes: function(){}, csi: function(){} };
            Object.defineProperty(navigator, 'languages', { get: () => ['en-AU', 'en-US', 'en'] });
            Object.defineProperty(navigator, 'hardwareConcurrency', { get: () => 8 });
            Object.defineProperty(navigator, 'platform', { get: () => 'Win32' });
        """)

        # LOGIN
        if not login(page, code=args.code):
            print("[FATAL] Login failed")
            sys.stdout.flush()
            browser.close()
            return

        # GO TO DASHBOARD + EXPAND ALL DOMAINS
        go_to_dashboard(page)

        if args.configure or args.domain:
            # Configure mode
            if args.domain:
                domains = {args.domain: domain_map.get(args.domain, args.domain)}
            else:
                domains = domain_map

            print(f"\n{'='*60}")
            print(f"CONFIGURING DNS — {len(domains)} domains")
            print(f"{'='*60}\n")
            sys.stdout.flush()

            results = []

            for i, (domain, netlify_sub) in enumerate(domains.items(), 1):
                print(f"\n[{i}/{len(domains)}] {domain} → {netlify_sub}.netlify.app")
                sys.stdout.flush()

                # Navigate to dashboard first
                if i > 1:
                    go_to_dashboard(page)

                # Click DNS button for this domain
                if click_dns_for_domain(page, domain):
                    print(f"  [DNS] Navigated to DNS page: {page.url}")
                    sys.stdout.flush()

                    # Configure DNS records
                    result = configure_dns(page, domain, netlify_sub)
                    results.append(result)
                    print(f"  → {result['status']} | A={result['a_record']} CNAME={result['cname_record']}")
                    sys.stdout.flush()
                else:
                    print(f"  [SKIP] Could not find DNS button for {domain}")
                    sys.stdout.flush()
                    results.append({
                        "domain": domain,
                        "netlify": f"{netlify_sub}.netlify.app",
                        "status": "dns_button_not_found",
                        "a_record": False,
                        "cname_record": False,
                    })

                time.sleep(1)

            # Save results
            results_path = OUTPUT_DIR / "ventraip_dns_results.json"
            with open(results_path, "w") as f:
                json.dump(results, f, indent=2)

            configured = sum(1 for r in results if r["status"] == "configured")
            partial = sum(1 for r in results if r["status"] == "partial")
            failed = len(results) - configured - partial
            print(f"\n{'='*60}")
            print(f"DONE: {configured} configured, {partial} partial, {failed} failed")
            print(f"Results: {results_path}")
            print(f"{'='*60}")
            sys.stdout.flush()

        else:
            # Explore mode — just look at the first domain's DNS page
            first_domain = list(domain_map.keys())[0]
            print(f"\n[EXPLORE] Looking for DNS page of {first_domain}...")
            sys.stdout.flush()

            if click_dns_for_domain(page, first_domain):
                print(f"  [EXPLORE] DNS page URL: {page.url}")
                sys.stdout.flush()
                explore_dns_page(page, first_domain)
            else:
                print(f"  [EXPLORE] Could not find DNS button for {first_domain}")
                sys.stdout.flush()

                # Dump the full page for analysis
                page.screenshot(path=str(SCREENSHOT_DIR / "v2_dashboard_debug.png"))
                html = page.content()
                debug_path = SCREENSHOT_DIR / "v2_dashboard_debug.html"
                debug_path.write_text(html[:200000], encoding="utf-8")
                print(f"  [EXPLORE] Dashboard HTML dumped to: {debug_path}")
                sys.stdout.flush()

        browser.close()
        print("\n[DONE] Browser closed")
        sys.stdout.flush()


if __name__ == "__main__":
    main()
