"""
SiliconBridge AutoDetect — Automatic verification barrier detection and resolution.

Wraps your browser automation (Playwright, Selenium) and automatically detects
when your agent hits verification barriers like CAPTCHAs, OTPs, phone verification,
or KYC flows. When detected, it routes to SiliconBridge human operators automatically.

Usage:
    from siliconbridge import SiliconBridge
    from siliconbridge.autodetect import AutoDetect

    sb = SiliconBridge("sb_your_key")
    detector = AutoDetect(sb)

    # With Playwright
    page = browser.new_page()
    detector.watch_playwright(page)
    # Now your agent just works — barriers are auto-resolved

    # With Selenium
    detector.watch_selenium(driver)

    # Standalone detection on any HTML
    barriers = detector.detect(page_html)
"""

import re
import time
import logging
from typing import Optional, List, Dict, Any

logger = logging.getLogger("siliconbridge.autodetect")


# Patterns that indicate verification barriers
BARRIER_PATTERNS = {
    "captcha": {
        "selectors": [
            'iframe[src*="recaptcha"]',
            'iframe[src*="hcaptcha"]',
            'iframe[src*="turnstile"]',
            '.g-recaptcha',
            '.h-captcha',
            '#captcha',
            '[data-captcha]',
            'img[alt*="captcha" i]',
            'img[alt*="CAPTCHA"]',
            'input[name*="captcha" i]',
            '.cf-turnstile',
        ],
        "text_patterns": [
            r"solve the captcha",
            r"verify you.?re? (human|not a robot)",
            r"complete the (security )?challenge",
            r"click.+to (verify|prove)",
            r"i.?m not a robot",
        ],
        "service": "captcha_solve",
    },
    "otp": {
        "selectors": [
            'input[name*="otp" i]',
            'input[name*="verification_code" i]',
            'input[name*="verify_code" i]',
            'input[name*="2fa" i]',
            'input[name*="totp" i]',
            'input[name*="mfa" i]',
            'input[placeholder*="code" i]',
            'input[placeholder*="OTP" i]',
            'input[autocomplete="one-time-code"]',
            # Pattern: 4-6 individual digit inputs in a row
            'input[maxlength="1"][type="tel"]',
            'input[maxlength="1"][type="number"]',
            'input[maxlength="1"][inputmode="numeric"]',
        ],
        "text_patterns": [
            r"enter.+(verification|security|confirmation) code",
            r"(we.?ve? )?sent.+code.+to",
            r"check your (phone|email|inbox)",
            r"enter the \d.digit code",
            r"two.factor authentication",
            r"verify your (phone|email|identity)",
            r"one.time (password|code|passcode)",
            r"authentication code",
        ],
        "service": "otp",
    },
    "phone_verification": {
        "selectors": [
            'input[type="tel"]',
            'input[name*="phone" i]',
            'input[placeholder*="phone" i]',
            'input[placeholder*"+1" i]',
            'select[name*="country_code" i]',
        ],
        "text_patterns": [
            r"verify your phone",
            r"enter your (phone|mobile) number",
            r"we.?ll (call|text|send).+(you|code)",
            r"phone verification",
            r"confirm your (phone|mobile)",
            r"sms verification",
        ],
        "service": "phone_verification",
    },
    "kyc": {
        "selectors": [
            'input[type="file"][accept*="image"]',
            'input[name*="document" i]',
            'input[name*="passport" i]',
            'input[name*="license" i]',
            'input[name*="identity" i]',
            '[data-upload*="id" i]',
            '[data-upload*="document" i]',
        ],
        "text_patterns": [
            r"upload.+(id|identity|passport|license|document)",
            r"verify your identity",
            r"identity verification",
            r"know your customer",
            r"proof of (identity|address|residence)",
            r"scan your (id|passport|license)",
            r"take a (selfie|photo)",
            r"government.issued (id|photo)",
        ],
        "service": "kyc_verification",
    },
    "approval": {
        "selectors": [],
        "text_patterns": [
            r"awaiting (approval|review|confirmation)",
            r"pending (human |manual )?review",
            r"requires? (human |manual )?(approval|verification|review)",
            r"contact (support|admin|us) to (proceed|continue|verify)",
            r"account (under |is )?(review|suspended|restricted)",
        ],
        "service": "approval",
    },
}


class BarrierDetected:
    """Represents a detected verification barrier."""

    def __init__(self, barrier_type: str, service: str, confidence: float,
                 evidence: List[str], screenshot_url: str = None):
        self.barrier_type = barrier_type
        self.service = service
        self.confidence = confidence
        self.evidence = evidence
        self.screenshot_url = screenshot_url

    def __repr__(self):
        return f"<Barrier type={self.barrier_type} service={self.service} confidence={self.confidence:.0%}>"

    def to_dict(self):
        return {
            "type": self.barrier_type,
            "service": self.service,
            "confidence": self.confidence,
            "evidence": self.evidence,
            "screenshot_url": self.screenshot_url,
        }


class AutoDetect:
    """
    Automatic verification barrier detector for AI agents.

    Watches browser sessions and auto-detects CAPTCHAs, OTPs, phone verification,
    KYC flows, and other human verification barriers. When detected, automatically
    routes to SiliconBridge human operators.
    """

    def __init__(self, client, auto_resolve: bool = True, confidence_threshold: float = 0.6,
                 on_barrier=None, on_resolved=None):
        """
        Args:
            client: SiliconBridge client instance
            auto_resolve: If True, automatically submit barriers to SiliconBridge
            confidence_threshold: Minimum confidence to trigger (0.0 - 1.0)
            on_barrier: Optional callback(barrier: BarrierDetected) when barrier found
            on_resolved: Optional callback(barrier, result) when barrier resolved
        """
        self.client = client
        self.auto_resolve = auto_resolve
        self.confidence_threshold = confidence_threshold
        self.on_barrier = on_barrier
        self.on_resolved = on_resolved
        self._watching = False

    def detect(self, html: str, page_url: str = "") -> List[BarrierDetected]:
        """
        Detect verification barriers in HTML content.

        Args:
            html: Page HTML content
            page_url: Current page URL (for context)

        Returns:
            List of detected barriers sorted by confidence
        """
        barriers = []
        html_lower = html.lower()

        for barrier_type, config in BARRIER_PATTERNS.items():
            evidence = []
            score = 0.0

            # Check for selector patterns in HTML
            for selector in config["selectors"]:
                # Convert CSS selector to a rough HTML pattern check
                pattern = self._selector_to_pattern(selector)
                if pattern and re.search(pattern, html, re.IGNORECASE):
                    evidence.append(f"Found element: {selector}")
                    score += 0.3

            # Check for text patterns
            for pattern in config["text_patterns"]:
                match = re.search(pattern, html_lower)
                if match:
                    evidence.append(f"Found text: '{match.group()}'")
                    score += 0.4

            # Cap confidence at 1.0
            confidence = min(score, 1.0)

            if confidence >= self.confidence_threshold and evidence:
                barriers.append(BarrierDetected(
                    barrier_type=barrier_type,
                    service=config["service"],
                    confidence=confidence,
                    evidence=evidence,
                ))

        # Sort by confidence descending
        barriers.sort(key=lambda b: b.confidence, reverse=True)
        return barriers

    def detect_and_resolve(self, html: str, page_url: str = "",
                           screenshot_url: str = None,
                           timeout: int = 300) -> Optional[Dict[str, Any]]:
        """
        Detect barriers and automatically resolve via SiliconBridge.

        Args:
            html: Page HTML
            page_url: Current URL
            screenshot_url: URL to a screenshot of the page
            timeout: Max seconds to wait for resolution

        Returns:
            Resolution result dict, or None if no barriers found
        """
        barriers = self.detect(html, page_url)
        if not barriers:
            return None

        barrier = barriers[0]  # Resolve highest confidence first
        barrier.screenshot_url = screenshot_url

        if self.on_barrier:
            self.on_barrier(barrier)

        logger.info(f"Barrier detected: {barrier.barrier_type} (confidence={barrier.confidence:.0%})")

        if not self.auto_resolve:
            return barrier.to_dict()

        # Route to appropriate SiliconBridge service
        result = self._resolve(barrier, page_url, screenshot_url, timeout)

        if self.on_resolved:
            self.on_resolved(barrier, result)

        return result

    def _resolve(self, barrier: BarrierDetected, page_url: str = "",
                 screenshot_url: str = None, timeout: int = 300) -> Dict[str, Any]:
        """Route a barrier to the appropriate SiliconBridge service."""

        if barrier.service == "captcha_solve":
            task = self.client.submit_task("captcha_solve", {
                "image_url": screenshot_url or page_url,
                "page_url": page_url,
                "instructions": f"Solve the CAPTCHA on this page. Evidence: {', '.join(barrier.evidence[:2])}",
            })
        elif barrier.service == "otp":
            task = self.client.submit_task("otp", {
                "page_url": page_url,
                "instructions": f"An OTP/verification code is needed. Evidence: {', '.join(barrier.evidence[:2])}",
            })
        elif barrier.service == "phone_verification":
            task = self.client.submit_task("phone_verification", {
                "page_url": page_url,
                "instructions": f"Phone verification required. Evidence: {', '.join(barrier.evidence[:2])}",
            })
        elif barrier.service == "kyc_verification":
            task = self.client.submit_task("identity_verify", {
                "page_url": page_url,
                "instructions": f"KYC/identity verification required. Evidence: {', '.join(barrier.evidence[:2])}",
            })
        elif barrier.service == "approval":
            task = self.client.submit_task("approval", {
                "action": f"Resolve blocked automation at {page_url}",
                "context": f"Agent blocked by: {', '.join(barrier.evidence[:2])}",
            })
        else:
            task = self.client.submit_task("custom", {
                "instructions": f"Resolve verification barrier: {barrier.barrier_type} at {page_url}",
                "evidence": barrier.evidence,
            })

        # Wait for resolution
        result = self.client.wait_for_result(task["task_id"], timeout=timeout)
        return {
            "barrier": barrier.to_dict(),
            "resolution": result,
            "status": "resolved",
        }

    def watch_playwright(self, page, poll_interval: float = 2.0):
        """
        Watch a Playwright page for verification barriers.
        Automatically detects and resolves barriers as the agent browses.

        Args:
            page: Playwright Page object
            poll_interval: Seconds between checks
        """
        import threading

        def _watch():
            self._watching = True
            while self._watching:
                try:
                    html = page.content()
                    url = page.url
                    barriers = self.detect(html, url)
                    if barriers:
                        barrier = barriers[0]
                        if barrier.confidence >= self.confidence_threshold:
                            logger.info(f"Auto-detected {barrier.barrier_type} on {url}")
                            # Take screenshot
                            screenshot_bytes = page.screenshot()
                            # TODO: Upload screenshot and get URL
                            self.detect_and_resolve(html, url)
                except Exception as e:
                    logger.debug(f"Watch cycle error: {e}")
                time.sleep(poll_interval)

        thread = threading.Thread(target=_watch, daemon=True)
        thread.start()
        logger.info("Playwright watcher started")

    def watch_selenium(self, driver, poll_interval: float = 2.0):
        """
        Watch a Selenium WebDriver for verification barriers.

        Args:
            driver: Selenium WebDriver
            poll_interval: Seconds between checks
        """
        import threading

        def _watch():
            self._watching = True
            while self._watching:
                try:
                    html = driver.page_source
                    url = driver.current_url
                    barriers = self.detect(html, url)
                    if barriers:
                        barrier = barriers[0]
                        if barrier.confidence >= self.confidence_threshold:
                            logger.info(f"Auto-detected {barrier.barrier_type} on {url}")
                            self.detect_and_resolve(html, url)
                except Exception as e:
                    logger.debug(f"Watch cycle error: {e}")
                time.sleep(poll_interval)

        thread = threading.Thread(target=_watch, daemon=True)
        thread.start()
        logger.info("Selenium watcher started")

    def stop(self):
        """Stop watching for barriers."""
        self._watching = False

    @staticmethod
    def _selector_to_pattern(selector: str) -> Optional[str]:
        """Convert a CSS selector to a rough regex pattern for HTML matching."""
        # iframe[src*="recaptcha"] -> <iframe[^>]+src="[^"]*recaptcha[^"]*"
        m = re.match(r'(\w+)\[(\w+)\*="([^"]+)"\]', selector)
        if m:
            tag, attr, val = m.groups()
            return rf'<{tag}[^>]+{attr}="[^"]*{re.escape(val)}[^"]*"'

        # .classname -> class="[^"]*classname[^"]*"
        m = re.match(r'\.([a-zA-Z0-9_-]+)', selector)
        if m:
            return rf'class="[^"]*{re.escape(m.group(1))}[^"]*"'

        # #id -> id="idname"
        m = re.match(r'#([a-zA-Z0-9_-]+)', selector)
        if m:
            return rf'id="{re.escape(m.group(1))}"'

        # [data-attr] -> data-attr
        m = re.match(r'\[([a-zA-Z0-9_-]+)\]', selector)
        if m:
            return re.escape(m.group(1))

        # tag[attr*="val" i] -> <tag[^>]+attr="[^"]*val
        m = re.match(r'(\w+)\[(\w+)\*="([^"]+)"\s*i?\]', selector)
        if m:
            tag, attr, val = m.groups()
            return rf'<{tag}[^>]+{attr}="[^"]*{re.escape(val)}'

        return None
