#!/usr/bin/env python3
"""
Final QA Proof Agent for talkingwidget.ai
Runs all 15 tests against both talkingwidget.ai and sunaiva-talking-widget.netlify.app
"""

import json
import os
import sys
from datetime import datetime
from playwright.sync_api import sync_playwright

# Targets
PRIMARY_URL = "https://talkingwidget.ai"
FALLBACK_URL = "https://sunaiva-talking-widget.netlify.app"
SCREENSHOT_DIR = "/mnt/e/genesis-system/qa_reports"

results = {}
screenshot_inventory = []

def log(msg):
    print(f"[{datetime.now().strftime('%H:%M:%S')}] {msg}")

def run_tests():
    with sync_playwright() as p:
        browser = p.chromium.launch(headless=True, args=["--no-sandbox"])

        # ============================================================
        # TEST 1: HTTP 200 check for talkingwidget.ai
        # ============================================================
        log("TEST 1: HTTP 200 check for talkingwidget.ai")
        try:
            ctx1 = browser.new_context(ignore_https_errors=False)
            page1 = ctx1.new_page()
            resp = page1.goto(PRIMARY_URL, timeout=15000, wait_until="domcontentloaded")
            status = resp.status if resp else 0
            results["test_01_http_200"] = {
                "name": "HTTP 200 — talkingwidget.ai",
                "status": "PASS" if status == 200 else "FAIL",
                "detail": f"HTTP {status}",
                "url": PRIMARY_URL
            }
            log(f"  -> HTTP {status}")
            ctx1.close()
        except Exception as e:
            results["test_01_http_200"] = {
                "name": "HTTP 200 — talkingwidget.ai",
                "status": "FAIL",
                "detail": f"Exception: {str(e)[:200]}",
                "url": PRIMARY_URL,
                "note": "DNS likely not yet propagated — testing against Netlify fallback"
            }
            log(f"  -> FAIL: {e}")

        # Determine active URL for content tests
        # Try primary first, fall back to Netlify
        active_url = PRIMARY_URL
        try:
            ctx_test = browser.new_context(ignore_https_errors=False)
            page_test = ctx_test.new_page()
            r = page_test.goto(PRIMARY_URL, timeout=10000, wait_until="domcontentloaded")
            if not r or r.status != 200:
                active_url = FALLBACK_URL
                log(f"  -> Primary not ready, using fallback: {FALLBACK_URL}")
            else:
                log(f"  -> Primary is live, using: {PRIMARY_URL}")
            ctx_test.close()
        except:
            active_url = FALLBACK_URL
            log(f"  -> Primary unreachable, using fallback: {FALLBACK_URL}")

        # ============================================================
        # MAIN CONTENT TESTS (2-15) — on active_url
        # ============================================================
        ctx = browser.new_context(
            viewport={"width": 1440, "height": 900},
            ignore_https_errors=False
        )
        page = ctx.new_page()

        log(f"Loading main page: {active_url}")
        page.goto(active_url, timeout=30000, wait_until="networkidle")
        page.wait_for_timeout(2000)

        # ============================================================
        # TEST 2: Page Title
        # ============================================================
        log("TEST 2: Correct page title")
        expected_title = "Talking Website Widget - Turn Your Website Into A Voice AI Assistant | Sunaiva"
        actual_title = page.title()
        title_match = expected_title.lower() in actual_title.lower() or actual_title.lower() in expected_title.lower()
        # Also check partial match for core keywords
        title_keywords = ["talking", "widget", "voice", "sunaiva"]
        keyword_match = all(kw in actual_title.lower() for kw in title_keywords[:3])
        results["test_02_title"] = {
            "name": "Correct page title",
            "status": "PASS" if (title_match or keyword_match) else "FAIL",
            "detail": f"Actual: '{actual_title}'",
            "expected": expected_title,
            "url": active_url
        }
        log(f"  -> Title: '{actual_title}'")

        # ============================================================
        # TEST 3: H1 Heading
        # ============================================================
        log("TEST 3: H1 heading — 'Your Website Can Talk Now'")
        try:
            h1_text = page.locator("h1").first.inner_text(timeout=5000).strip()
            h1_pass = "your website can talk now" in h1_text.lower() or "talk now" in h1_text.lower()
            results["test_03_h1"] = {
                "name": "H1 heading — 'Your Website Can Talk Now'",
                "status": "PASS" if h1_pass else "FAIL",
                "detail": f"H1: '{h1_text}'",
                "url": active_url
            }
            log(f"  -> H1: '{h1_text}'")
        except Exception as e:
            results["test_03_h1"] = {
                "name": "H1 heading — 'Your Website Can Talk Now'",
                "status": "FAIL",
                "detail": f"Exception: {str(e)[:200]}",
                "url": active_url
            }
            log(f"  -> FAIL: {e}")

        # ============================================================
        # TEST 4: Pricing Tier 1 — "Starter" + "$497"
        # ============================================================
        log("TEST 4: Pricing Tier 1 — Starter + $497")
        page_content = page.content()
        page_text = page.inner_text("body")

        starter_present = "starter" in page_text.lower()
        price_497_present = "497" in page_text
        results["test_04_tier1"] = {
            "name": "Pricing Tier 1 — Starter + $497",
            "status": "PASS" if (starter_present and price_497_present) else "FAIL",
            "detail": f"'Starter' found: {starter_present}, '$497' found: {price_497_present}",
            "url": active_url
        }
        log(f"  -> Starter: {starter_present}, $497: {price_497_present}")

        # ============================================================
        # TEST 5: Pricing Tier 2 — "High-Use" or "Business" + "$997"
        # ============================================================
        log("TEST 5: Pricing Tier 2 — High-Use/Business + $997")
        tier2_name = ("high-use" in page_text.lower() or "high use" in page_text.lower() or
                      "business" in page_text.lower() or "professional" in page_text.lower())
        price_997 = "997" in page_text
        results["test_05_tier2"] = {
            "name": "Pricing Tier 2 — High-Use/Business + $997",
            "status": "PASS" if (tier2_name and price_997) else "FAIL",
            "detail": f"Tier2 name found: {tier2_name}, '$997' found: {price_997}",
            "url": active_url
        }
        log(f"  -> Tier2 name: {tier2_name}, $997: {price_997}")

        # ============================================================
        # TEST 6: Pricing Tier 3 — "Enterprise" + "$1,497"
        # ============================================================
        log("TEST 6: Pricing Tier 3 — Enterprise + $1,497")
        enterprise_present = "enterprise" in page_text.lower()
        price_1497 = "1,497" in page_text or "1497" in page_text
        results["test_06_tier3"] = {
            "name": "Pricing Tier 3 — Enterprise + $1,497",
            "status": "PASS" if (enterprise_present and price_1497) else "FAIL",
            "detail": f"'Enterprise' found: {enterprise_present}, '$1,497' found: {price_1497}",
            "url": active_url
        }
        log(f"  -> Enterprise: {enterprise_present}, $1,497: {price_1497}")

        # ============================================================
        # TEST 7: NO old $297 pricing
        # ============================================================
        log("TEST 7: NO old $297 pricing on page")
        price_297 = "297" in page_text
        results["test_07_no_297"] = {
            "name": "NO old $297 pricing",
            "status": "PASS" if not price_297 else "FAIL",
            "detail": f"$297 found on page: {price_297}",
            "url": active_url
        }
        log(f"  -> $297 found (should be False): {price_297}")

        # ============================================================
        # TEST 8: Telnyx widget element in DOM
        # ============================================================
        log("TEST 8: Telnyx <telnyx-ai-agent> element in DOM")
        try:
            # Check both in HTML source and via JS
            telnyx_in_html = "telnyx-ai-agent" in page_content
            telnyx_via_js = page.evaluate(
                "() => !!document.querySelector('telnyx-ai-agent')"
            )
            telnyx_present = telnyx_in_html or telnyx_via_js
            results["test_08_telnyx_widget"] = {
                "name": "Telnyx <telnyx-ai-agent> element present",
                "status": "PASS" if telnyx_present else "FAIL",
                "detail": f"In HTML: {telnyx_in_html}, Via JS querySelector: {telnyx_via_js}",
                "url": active_url
            }
            log(f"  -> In HTML: {telnyx_in_html}, Via JS: {telnyx_via_js}")
        except Exception as e:
            results["test_08_telnyx_widget"] = {
                "name": "Telnyx <telnyx-ai-agent> element present",
                "status": "FAIL",
                "detail": f"Exception: {str(e)[:200]}",
                "url": active_url
            }
            log(f"  -> FAIL: {e}")

        # ============================================================
        # TEST 9: robots.txt
        # ============================================================
        log("TEST 9: robots.txt check")
        robots_url = f"{active_url}/robots.txt"
        # Use primary URL for robots if DNS resolved
        robots_primary = f"{PRIMARY_URL}/robots.txt"
        try:
            ctx_robots = browser.new_context()
            page_robots = ctx_robots.new_page()

            # Try primary first
            target_robots = robots_primary
            try:
                r = page_robots.goto(robots_primary, timeout=10000)
                if not r or r.status != 200:
                    target_robots = f"{FALLBACK_URL}/robots.txt"
                    page_robots.goto(target_robots, timeout=10000)
            except:
                target_robots = f"{FALLBACK_URL}/robots.txt"
                page_robots.goto(target_robots, timeout=10000)

            robots_text = page_robots.inner_text("body") if page_robots.url else ""
            content_type = page_robots.evaluate(
                "() => document.contentType || 'unknown'"
            )
            robots_pass = "user-agent" in robots_text.lower() and ("*" in robots_text or "allow" in robots_text.lower())
            results["test_09_robots"] = {
                "name": "robots.txt — text/plain with User-agent: *",
                "status": "PASS" if robots_pass else "FAIL",
                "detail": f"Content: '{robots_text[:200].strip()}', ContentType: {content_type}",
                "url": target_robots
            }
            log(f"  -> robots.txt: '{robots_text[:80].strip()}'")
            ctx_robots.close()
        except Exception as e:
            results["test_09_robots"] = {
                "name": "robots.txt — text/plain with User-agent: *",
                "status": "FAIL",
                "detail": f"Exception: {str(e)[:200]}",
                "url": robots_url
            }
            log(f"  -> FAIL: {e}")

        # ============================================================
        # TEST 10: sitemap.xml
        # ============================================================
        log("TEST 10: sitemap.xml check")
        try:
            ctx_sm = browser.new_context()
            page_sm = ctx_sm.new_page()

            sitemap_primary = f"{PRIMARY_URL}/sitemap.xml"
            sitemap_fallback = f"{FALLBACK_URL}/sitemap.xml"

            target_sm = sitemap_primary
            try:
                r = page_sm.goto(sitemap_primary, timeout=10000)
                if not r or r.status != 200:
                    target_sm = sitemap_fallback
                    page_sm.goto(target_sm, timeout=10000)
            except:
                target_sm = sitemap_fallback
                page_sm.goto(target_sm, timeout=10000)

            sm_content = page_sm.content()
            sm_text = page_sm.inner_text("body") if page_sm.url else ""
            is_xml = "<?xml" in sm_content or "<urlset" in sm_content or "<sitemapindex" in sm_content
            has_urls = "talkingwidget.ai" in sm_content or "sunaiva" in sm_content.lower() or "<url>" in sm_content or "<loc>" in sm_content
            results["test_10_sitemap"] = {
                "name": "sitemap.xml — XML with talkingwidget.ai URLs",
                "status": "PASS" if (is_xml and has_urls) else "FAIL",
                "detail": f"Is XML: {is_xml}, Has URLs: {has_urls}, Content preview: '{sm_content[:200]}'",
                "url": target_sm
            }
            log(f"  -> Is XML: {is_xml}, Has URLs: {has_urls}")
            ctx_sm.close()
        except Exception as e:
            results["test_10_sitemap"] = {
                "name": "sitemap.xml — XML with talkingwidget.ai URLs",
                "status": "FAIL",
                "detail": f"Exception: {str(e)[:200]}",
                "url": f"{active_url}/sitemap.xml"
            }
            log(f"  -> FAIL: {e}")

        # ============================================================
        # TEST 11: Privacy page
        # ============================================================
        log("TEST 11: Privacy page")
        try:
            ctx_p = browser.new_context()
            page_p = ctx_p.new_page()

            privacy_primary = f"{PRIMARY_URL}/privacy.html"
            privacy_fallback = f"{FALLBACK_URL}/privacy.html"

            target_priv = privacy_primary
            r = None
            try:
                r = page_p.goto(privacy_primary, timeout=10000, wait_until="domcontentloaded")
                if not r or r.status != 200:
                    target_priv = privacy_fallback
                    r = page_p.goto(target_priv, timeout=10000, wait_until="domcontentloaded")
            except:
                target_priv = privacy_fallback
                r = page_p.goto(target_priv, timeout=10000, wait_until="domcontentloaded")

            priv_status = r.status if r else 0
            priv_text = page_p.inner_text("body")
            privacy_keywords = any(kw in priv_text.lower() for kw in ["privacy", "personal information", "data", "collect"])
            results["test_11_privacy"] = {
                "name": "Privacy page — returns 200 with privacy content",
                "status": "PASS" if (priv_status == 200 and privacy_keywords) else "FAIL",
                "detail": f"HTTP {priv_status}, Privacy keywords found: {privacy_keywords}",
                "url": target_priv
            }
            log(f"  -> HTTP {priv_status}, keywords: {privacy_keywords}")
            ctx_p.close()
        except Exception as e:
            results["test_11_privacy"] = {
                "name": "Privacy page — returns 200 with privacy content",
                "status": "FAIL",
                "detail": f"Exception: {str(e)[:200]}",
                "url": f"{active_url}/privacy.html"
            }
            log(f"  -> FAIL: {e}")

        # ============================================================
        # TEST 12: Terms page
        # ============================================================
        log("TEST 12: Terms page")
        try:
            ctx_t = browser.new_context()
            page_t = ctx_t.new_page()

            terms_primary = f"{PRIMARY_URL}/terms.html"
            terms_fallback = f"{FALLBACK_URL}/terms.html"

            target_terms = terms_primary
            r = None
            try:
                r = page_t.goto(terms_primary, timeout=10000, wait_until="domcontentloaded")
                if not r or r.status != 200:
                    target_terms = terms_fallback
                    r = page_t.goto(target_terms, timeout=10000, wait_until="domcontentloaded")
            except:
                target_terms = terms_fallback
                r = page_t.goto(target_terms, timeout=10000, wait_until="domcontentloaded")

            terms_status = r.status if r else 0
            terms_text = page_t.inner_text("body")
            terms_keywords = any(kw in terms_text.lower() for kw in ["terms", "service", "agreement", "use", "liability"])
            results["test_12_terms"] = {
                "name": "Terms page — returns 200 with terms content",
                "status": "PASS" if (terms_status == 200 and terms_keywords) else "FAIL",
                "detail": f"HTTP {terms_status}, Terms keywords found: {terms_keywords}",
                "url": target_terms
            }
            log(f"  -> HTTP {terms_status}, keywords: {terms_keywords}")
            ctx_t.close()
        except Exception as e:
            results["test_12_terms"] = {
                "name": "Terms page — returns 200 with terms content",
                "status": "FAIL",
                "detail": f"Exception: {str(e)[:200]}",
                "url": f"{active_url}/terms.html"
            }
            log(f"  -> FAIL: {e}")

        # ============================================================
        # TEST 13: Mobile responsive — 375px viewport
        # ============================================================
        log("TEST 13: Mobile responsive at 375px")
        try:
            ctx_mobile = browser.new_context(
                viewport={"width": 375, "height": 812},
                user_agent="Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Mobile/15E148 Safari/604.1"
            )
            page_mobile = ctx_mobile.new_page()
            page_mobile.goto(active_url, timeout=30000, wait_until="networkidle")
            page_mobile.wait_for_timeout(2000)

            # Check for horizontal overflow
            scroll_width = page_mobile.evaluate("() => document.documentElement.scrollWidth")
            client_width = page_mobile.evaluate("() => document.documentElement.clientWidth")
            inner_width = page_mobile.evaluate("() => window.innerWidth")

            no_overflow = scroll_width <= client_width or scroll_width <= inner_width + 5  # 5px tolerance

            # Scroll to pricing section for screenshot
            try:
                page_mobile.evaluate("() => { const el = document.querySelector('#pricing, .pricing, [data-section=\"pricing\"]'); if(el) el.scrollIntoView(); }")
                page_mobile.wait_for_timeout(500)
            except:
                pass

            # Mobile pricing screenshot
            mobile_ss = f"{SCREENSHOT_DIR}/final_proof_mobile.png"
            page_mobile.screenshot(path=mobile_ss, full_page=False)
            screenshot_inventory.append(("final_proof_mobile.png", "Mobile 375px viewport — pricing section"))

            results["test_13_mobile"] = {
                "name": "Mobile responsive — 375px, no horizontal overflow",
                "status": "PASS" if no_overflow else "FAIL",
                "detail": f"scrollWidth={scroll_width}, clientWidth={client_width}, innerWidth={inner_width}, overflow={not no_overflow}",
                "url": active_url,
                "screenshot": mobile_ss
            }
            log(f"  -> scrollWidth={scroll_width}, clientWidth={client_width}, overflow={not no_overflow}")
            ctx_mobile.close()
        except Exception as e:
            results["test_13_mobile"] = {
                "name": "Mobile responsive — 375px, no horizontal overflow",
                "status": "FAIL",
                "detail": f"Exception: {str(e)[:200]}",
                "url": active_url
            }
            log(f"  -> FAIL: {e}")

        # ============================================================
        # TEST 14: HTTPS/SSL — verify no SSL errors
        # ============================================================
        log("TEST 14: HTTPS/SSL check")
        try:
            ctx_ssl = browser.new_context(ignore_https_errors=False)
            page_ssl = ctx_ssl.new_page()
            ssl_errors = []

            def handle_ssl_err(req):
                pass

            # Navigate — if SSL error, it would throw
            r = page_ssl.goto(active_url, timeout=15000, wait_until="domcontentloaded")
            ssl_ok = r and r.status == 200
            protocol = page_ssl.evaluate("() => window.location.protocol")

            results["test_14_https"] = {
                "name": "HTTPS/SSL — loads over HTTPS with no errors",
                "status": "PASS" if (ssl_ok and protocol == "https:") else "FAIL",
                "detail": f"Protocol: {protocol}, HTTP Status: {r.status if r else 'None'}, SSL errors: none detected",
                "url": active_url
            }
            log(f"  -> Protocol: {protocol}, Status: {r.status if r else 'None'}")
            ctx_ssl.close()
        except Exception as e:
            results["test_14_https"] = {
                "name": "HTTPS/SSL — loads over HTTPS with no errors",
                "status": "FAIL",
                "detail": f"SSL/HTTPS Exception: {str(e)[:200]}",
                "url": active_url
            }
            log(f"  -> FAIL (SSL error): {e}")

        # ============================================================
        # TEST 15: Full page desktop screenshot at 1440px
        # ============================================================
        log("TEST 15: Full page desktop screenshot at 1440px")
        try:
            # page is already at 1440px viewport
            page.goto(active_url, timeout=30000, wait_until="networkidle")
            page.wait_for_timeout(3000)

            desktop_ss = f"{SCREENSHOT_DIR}/final_proof_desktop.png"
            page.screenshot(path=desktop_ss, full_page=True)
            screenshot_inventory.append(("final_proof_desktop.png", "Desktop 1440px full page"))

            # Check file was saved
            ss_size = os.path.getsize(desktop_ss) if os.path.exists(desktop_ss) else 0
            results["test_15_screenshot"] = {
                "name": "Full page desktop screenshot 1440px",
                "status": "PASS" if ss_size > 10000 else "FAIL",
                "detail": f"Screenshot saved: {desktop_ss}, Size: {ss_size} bytes",
                "url": active_url,
                "screenshot": desktop_ss
            }
            log(f"  -> Screenshot saved, size: {ss_size} bytes")
        except Exception as e:
            results["test_15_screenshot"] = {
                "name": "Full page desktop screenshot 1440px",
                "status": "FAIL",
                "detail": f"Exception: {str(e)[:200]}",
                "url": active_url
            }
            log(f"  -> FAIL: {e}")

        ctx.close()

        # ============================================================
        # ADDITIONAL: DNS check
        # ============================================================
        log("DNS: Checking talkingwidget.ai A record")
        import subprocess
        try:
            dig_result = subprocess.run(
                ["dig", "talkingwidget.ai", "A", "+short"],
                capture_output=True, text=True, timeout=10
            )
            dns_records = dig_result.stdout.strip()
            log(f"  -> DNS A records: '{dns_records}'")
        except:
            try:
                import socket
                dns_records = socket.gethostbyname("talkingwidget.ai")
                log(f"  -> DNS resolved: {dns_records}")
            except Exception as e:
                dns_records = f"Not resolved: {e}"
                log(f"  -> DNS not resolved: {e}")

        browser.close()

        return results, screenshot_inventory, active_url, dns_records

def main():
    log("=" * 60)
    log("FINAL QA PROOF — talkingwidget.ai")
    log("=" * 60)

    test_results, screenshots, active_url, dns_info = run_tests()

    # Save JSON results
    json_path = f"{SCREENSHOT_DIR}/final_qa_results.json"
    with open(json_path, "w") as f:
        json.dump({
            "timestamp": datetime.now().isoformat(),
            "active_url": active_url,
            "dns_info": dns_info,
            "results": test_results,
            "screenshots": screenshots
        }, f, indent=2)
    log(f"Results saved to: {json_path}")

    # Summary
    log("\n" + "=" * 60)
    log("RESULTS SUMMARY")
    log("=" * 60)
    pass_count = sum(1 for r in test_results.values() if r["status"] == "PASS")
    fail_count = sum(1 for r in test_results.values() if r["status"] == "FAIL")
    total = len(test_results)

    for key, r in sorted(test_results.items()):
        icon = "✓" if r["status"] == "PASS" else "✗"
        log(f"  {icon} {r['name']}: {r['status']}")
        log(f"    {r['detail'][:100]}")

    log(f"\nTotal: {pass_count}/{total} PASSED, {fail_count} FAILED")
    log(f"Active URL: {active_url}")
    log(f"DNS: {dns_info}")

if __name__ == "__main__":
    main()
