"""eBay site preset with fixed extractors."""
import time
import random
import re
import json
import logging

logger = logging.getLogger("iploop.sites.ebay")


class eBay:
    RATE_LIMIT = 15
    _last_request = 0

    def __init__(self, client):
        self.client = client

    def _rate_limit(self):
        elapsed = time.time() - eBay._last_request
        if elapsed < self.RATE_LIMIT:
            time.sleep(self.RATE_LIMIT - elapsed + random.uniform(0, 2))
        eBay._last_request = time.time()

    def _extract_text(self, html: str) -> str:
        """Strip HTML tags and return clean text."""
        # Remove HTML tags
        text = re.sub(r'<[^>]+>', '', html)
        # Clean up whitespace
        text = re.sub(r'\s+', ' ', text).strip()
        return text

    def _validate_ebay_results(self, html: str) -> bool:
        """Check if we got real eBay search results."""
        if not html:
            return False
        
        # Check for actual search results
        result_indicators = [
            'class="s-item"',
            'data-testid="item-card"',
            'class="srp-results"',
            'id="srp-river-results"',
            'class="s-item__title"',
            'class="s-item__price"',
            'class="s-card__title"',
            's-card__price',
            'class="s-card__link'
        ]
        
        return any(indicator in html for indicator in result_indicators)

    def _extract_ebay_products(self, html: str) -> list:
        """Extract product listings from eBay search results — supports both old and new HTML."""
        products = []

        # --- New eBay layout (2025+): su-card-container__content blocks ---
        card_chunks = re.split(r'class="su-card-container__content"', html)[1:]
        for chunk in card_chunks[:40]:
            # Title inside s-card__title > span
            title_match = re.search(r'class="s-card__title"[^>]*>\s*<span[^>]*>([^<]+)', chunk)
            title = self._extract_text(title_match.group(1)) if title_match else ""
            if title in ("", "Shop on eBay"):
                continue

            # Price — new class: s-card__price inside span
            price_match = re.search(r's-card__price[^>]*>([^<]+)', chunk)
            if not price_match:
                price_match = re.search(r'class="su-styled-text primary bold[^"]*"[^>]*>([^<]+)', chunk)
            price = self._extract_text(price_match.group(1)) if price_match else ""

            # URL from the card link
            url_match = re.search(r'href="([^"]+ebay\.com/itm/[^"]+)"', chunk)
            if not url_match:
                url_match = re.search(r'href="([^"]+)"', chunk)
            url = url_match.group(1).replace("&amp;", "&") if url_match else ""

            # Subtitle (condition/shipping)
            subtitle_match = re.search(r'class="s-card__subtitle"[^>]*>\s*<span[^>]*>([^<]+)', chunk)
            subtitle = self._extract_text(subtitle_match.group(1)) if subtitle_match else ""

            if title and price:
                products.append({"title": title, "price": price, "url": url, "condition": subtitle})

        if products:
            return products

        # --- Legacy eBay layout: s-item blocks ---
        item_chunks = re.split(r'<li[^>]*class="s-item\b', html)[1:]
        for item_html in item_chunks[:20]:
            title_match = re.search(r'class="s-item__title"[^>]*>(?:<[^>]*>)*([^<]+)', item_html)
            title = self._extract_text(title_match.group(1)) if title_match else ""

            price_match = re.search(r'<span class="s-item__price"[^>]*>([^<]+)', item_html)
            if not price_match:
                price_match = re.search(r'class="[^"]*price[^"]*"[^>]*>([^<]+)', item_html)
            price = self._extract_text(price_match.group(1)) if price_match else ""

            url_match = re.search(r'href="([^"]*)"', item_html)
            url = url_match.group(1) if url_match else ""

            if title and price:
                products.append({"title": title, "price": price, "url": url})

        return products

    def _extract_item_data(self, html: str, item_id: str) -> dict:
        """Extract item data from eBay item page."""
        data = {"item_id": item_id}
        
        # Extract title
        title_match = re.search(r'<h1[^>]*id="x-title-label-lbl"[^>]*>([^<]+)', html)
        if not title_match:
            title_match = re.search(r'<h1[^>]*class="[^"]*it-ttl[^"]*"[^>]*>([^<]+)', html)
        if title_match:
            data['title'] = title_match.group(1).strip()
        
        # Extract price
        price_match = re.search(r'class="u-flL[^"]*"[^>]*>([^<]+)', html)
        if not price_match:
            price_match = re.search(r'id="prcIsum"[^>]*>([^<]+)', html)
        if price_match:
            data['price'] = price_match.group(1).strip()
        
        # Extract condition
        condition_match = re.search(r'Condition:[^>]*>([^<]+)', html, re.IGNORECASE)
        if condition_match:
            data['condition'] = condition_match.group(1).strip()
        
        # Extract seller
        seller_match = re.search(r'class="mbg-nw"[^>]*>([^<]+)', html)
        if seller_match:
            data['seller'] = seller_match.group(1).strip()
        
        # Extract shipping
        shipping_match = re.search(r'Shipping:[^>]*>([^<]+)', html, re.IGNORECASE)
        if shipping_match:
            data['shipping'] = shipping_match.group(1).strip()
        
        return data

    def _fetch_with_browser(self, url, country="US"):
        """Fallback: render page with headless browser through IPLoop proxy."""
        try:
            from playwright.sync_api import sync_playwright
        except ImportError:
            logger.warning("playwright not installed — can't render JS. pip install playwright && playwright install chromium")
            return None

        proxy_url = self.client._get_proxy_url(country=country) if hasattr(self.client, '_get_proxy_url') else None

        try:
            pw = sync_playwright().start()
            launch_args = {"headless": True}
            if proxy_url:
                launch_args["proxy"] = {"server": proxy_url}
            browser = pw.chromium.launch(**launch_args)
            page = browser.new_page(
                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"
            )
            page.goto(url, timeout=30000, wait_until="domcontentloaded")
            # Wait for search results to render
            try:
                page.wait_for_selector('.s-item__title', timeout=10000)
            except Exception:
                pass
            html = page.content()
            browser.close()
            pw.stop()
            return html
        except Exception as e:
            logger.warning(f"Browser rendering failed: {e}")
            return None

    def search(self, query, country="US", extract=True):
        """Search eBay — tries plain HTTP first, falls back to headless browser for JS rendering."""
        self._rate_limit()
        import urllib.parse
        
        domain_map = {
            "US": "ebay.com",
            "UK": "ebay.co.uk", 
            "DE": "ebay.de",
            "FR": "ebay.fr",
            "CA": "ebay.ca",
            "AU": "ebay.com.au"
        }
        
        domain = domain_map.get(country, "ebay.com")
        encoded_query = urllib.parse.quote_plus(query)
        url = f"https://www.{domain}/sch/i.html?_nkw={encoded_query}"
        
        resp = self.client.fetch(url, country=country)
        html = resp.text
        source = "http"
        
        # If plain HTTP didn't get real results, try headless browser
        if resp.status_code == 200 and not self._validate_ebay_results(html):
            logger.info("eBay: plain HTTP got no results, trying headless browser...")
            browser_html = self._fetch_with_browser(url, country=country)
            if browser_html and self._validate_ebay_results(browser_html):
                html = browser_html
                source = "browser"
        
        result = {
            "query": query,
            "url": url,
            "status": resp.status_code,
            "html": html,
            "size_kb": len(html) // 1024,
            "source": source
        }
        
        if extract and resp.status_code == 200:
            if self._validate_ebay_results(html):
                result["products"] = self._extract_ebay_products(html)
            else:
                result["products"] = []
                logger.warning("eBay search returned no valid results (even with browser fallback)")
        
        return result

    def item(self, item_id, country="US", extract=True):
        """Fetch an eBay item page with extraction."""
        self._rate_limit()
        url = f"https://www.ebay.com/itm/{item_id}"
        
        resp = self.client.fetch(url, country=country)
        
        result = {
            "item_id": item_id,
            "url": url,
            "status": resp.status_code,
            "html": resp.text,
            "size_kb": len(resp.text) // 1024
        }
        
        if extract and resp.status_code == 200:
            result["data"] = self._extract_item_data(resp.text, item_id)
        
        return result

    def category(self, category_id, country="US"):
        """Browse eBay category."""
        self._rate_limit()
        domain = {"US": "ebay.com", "UK": "ebay.co.uk", "DE": "ebay.de"}.get(country, "ebay.com")
        url = f"https://www.{domain}/sch/i.html?_sacat={category_id}"
        
        resp = self.client.fetch(url, country=country)
        
        return {
            "category_id": category_id,
            "url": url,
            "status": resp.status_code,
            "html": resp.text
        }
