#!/usr/bin/env python3
"""
Enhanced Wildberries Product Data Fetcher

Extracts:
- Product images
- Product name, price, brand
- Full product description
- Customer reviews (top 5)

Category detection is delegated to Claude during story vision stage.
"""

import json
import re
import time
from typing import Dict, List, Optional


def fetch_wb_product_enhanced(url: str, headless: bool = True) -> Optional[Dict]:
    """
    Enhanced fetch with reviews and full description

    Args:
        url: WB product URL
        headless: Run browser in headless mode

    Returns:
        Product data dict with name, images, price, description, reviews
    """
    try:
        from playwright.sync_api import sync_playwright
    except ImportError:
        print("Playwright not installed. Install with: pip install playwright && playwright install chromium")
        return None

    with sync_playwright() as p:
        # Launch browser with stealth options
        browser = p.chromium.launch(
            headless=headless,
            args=[
                '--disable-blink-features=AutomationControlled',
                '--no-sandbox',
            ]
        )
        context = browser.new_context(
            viewport={"width": 1920, "height": 1080},
            user_agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
            locale="ru-RU"
        )
        page = context.new_page()

        # Hide webdriver detection
        page.add_init_script("""
            Object.defineProperty(navigator, 'webdriver', {get: () => undefined});
        """)

        try:
            # Navigate to product page
            print(f"Fetching: {url}")
            page.goto(url, wait_until="networkidle", timeout=30000)
            time.sleep(3)

            # Wait for images to load
            page.wait_for_selector('img[src*="wbbasket"]', timeout=15000)

            # Scroll to trigger lazy loading
            page.evaluate("window.scrollTo(0, 500)")
            time.sleep(1)

            # Extract basic product data
            product_data = page.evaluate("""() => {
                const result = {};

                // Extract name from page title
                const titleMatch = document.title.match(/^(.+?)\\s+\\d+\\s+купить/);
                result.name = titleMatch ? titleMatch[1].trim() : document.title;

                // Images - collect unique product images
                const images = [];
                const seenImages = new Set();
                document.querySelectorAll('img').forEach(img => {
                    const src = img.src || img.dataset.src;
                    if (src && src.includes('/images/') && src.includes('wbbasket') && !src.includes('logo')) {
                        const bigSrc = src
                            .replace('/tm/', '/big/')
                            .replace('/c246x328/', '/big/')
                            .replace('/c516x688/', '/big/');
                        const match = bigSrc.match(/\\/big\\/(\\d+)\\.webp/);
                        if (match && !seenImages.has(match[1])) {
                            seenImages.add(match[1]);
                            images.push(bigSrc);
                        }
                    }
                });
                result.images = images.sort((a, b) => {
                    const numA = parseInt(a.match(/\\/(\\d+)\\.webp/)?.[1] || 0);
                    const numB = parseInt(b.match(/\\/(\\d+)\\.webp/)?.[1] || 0);
                    return numA - numB;
                });

                // Price
                const priceSelectors = [
                    'ins.price-block__final-price',
                    '.price-block__final-price',
                    '[class*="price"] ins',
                    '.product-page__price-block ins'
                ];
                for (const sel of priceSelectors) {
                    const el = document.querySelector(sel);
                    if (el && el.textContent.match(/\\d/)) {
                        result.price = el.textContent.trim().replace(/\\s+/g, ' ');
                        break;
                    }
                }

                // Brand
                const brandEl = document.querySelector('[class*="brand"], .product-page__header-brand');
                result.brand = brandEl ? brandEl.textContent.trim() : '';

                // Full description - try multiple sources
                let description = '';

                // First try specific product detail selectors (NEW WB structure)
                const productDescSelectors = [
                    // New WB structure (2025+)
                    '[data-name="Description"]',
                    '.product-page__description-text',
                    '.product-detail__description',
                    // Collapsable sections with actual content
                    '.collapsable__content p',
                    '.collapsable__content div',
                    // Legacy selectors
                    '.product-page__description',
                    '.j-product-detail',
                    // Option detail blocks
                    '.option__text',
                    '.product-params__cell--value'
                ];

                for (const sel of productDescSelectors) {
                    const els = document.querySelectorAll(sel);
                    els.forEach(el => {
                        const text = el.textContent.trim().replace(/\\s+/g, ' ');
                        // Only use if it's actual product content (not site-wide description)
                        if (text.length > 50 &&
                            !text.includes('Коллекции женской, мужской') &&
                            !text.includes('Информация о доставке') &&
                            text.length > description.length) {
                            description = text;
                        }
                    });
                }

                // If still no description, try to build from characteristics
                if (description.length < 50) {
                    const charTexts = [];
                    document.querySelectorAll('[class*="characteristic"], [class*="params__row"]').forEach(row => {
                        const text = row.textContent.trim();
                        if (text.length > 10 && text.length < 200) {
                            charTexts.push(text);
                        }
                    });
                    if (charTexts.length > 0) {
                        description = charTexts.join('. ');
                    }
                }

                // Only use meta as last resort and only if it looks product-specific
                if (description.length < 50) {
                    const metaDesc = document.querySelector('meta[name="description"]');
                    if (metaDesc && metaDesc.content &&
                        !metaDesc.content.includes('Коллекции женской') &&
                        !metaDesc.content.includes('Wildberries')) {
                        description = metaDesc.content;
                    }
                }

                result.description = description.substring(0, 2000);

                // Product specifications/characteristics
                const specs = [];

                // Try new WB structure (2025+)
                document.querySelectorAll('.product-params tr, .characteristics tr, [class*="detail-char"] tr').forEach(row => {
                    const cells = row.querySelectorAll('td, th, [class*="cell"]');
                    if (cells.length >= 2) {
                        specs.push({
                            name: cells[0].textContent.trim(),
                            value: cells[1].textContent.trim()
                        });
                    }
                });

                // Try legacy structure
                if (specs.length === 0) {
                    document.querySelectorAll('.product-params__row, [class*="characteristic"]').forEach(row => {
                        const name = row.querySelector('[class*="name"], th, span:first-child');
                        const value = row.querySelector('[class*="value"], td, span:last-child');
                        if (name && value && name !== value) {
                            specs.push({
                                name: name.textContent.trim(),
                                value: value.textContent.trim()
                            });
                        }
                    });
                }

                // Try option blocks
                if (specs.length === 0) {
                    document.querySelectorAll('.option, [class*="option__"]').forEach(opt => {
                        const label = opt.querySelector('[class*="label"], [class*="title"]');
                        const value = opt.querySelector('[class*="value"], [class*="text"]');
                        if (label && value) {
                            specs.push({
                                name: label.textContent.trim(),
                                value: value.textContent.trim()
                            });
                        }
                    });
                }

                result.specifications = specs.slice(0, 30); // Limit specs

                return result;
            }""")

            # Extract product ID from URL
            match = re.search(r'/catalog/(\d+)/', url)
            if match:
                product_data['product_id'] = match.group(1)

            product_data['url'] = url

            # Now fetch reviews
            print("Fetching reviews...")
            reviews = fetch_reviews(page)
            product_data['reviews'] = reviews

            browser.close()
            return product_data

        except Exception as e:
            print(f"Error fetching product: {e}")
            browser.close()
            return None


def fetch_reviews(page) -> List[Dict]:
    """
    Fetch customer reviews for product

    Returns list of {rating, text, author, date}
    """
    reviews = []

    try:
        # Try to find and click reviews tab/section
        review_selectors = [
            '[data-link="feedbacks"]',
            '[href*="feedbacks"]',
            'button:has-text("Отзывы")',
            'a:has-text("Отзывы")',
            '[class*="reviews"]',
            '[data-tab="reviews"]'
        ]

        for selector in review_selectors:
            try:
                el = page.query_selector(selector)
                if el:
                    el.click()
                    time.sleep(2)
                    break
            except:
                continue

        # Scroll to load reviews
        page.evaluate("window.scrollTo(0, 1200)")
        time.sleep(2)

        # Extract reviews with updated selectors
        review_data = page.evaluate("""() => {
            const reviews = [];

            // WB 2025+ review structure: feedback__content contains actual review
            const reviewContainers = document.querySelectorAll(
                '.feedback__content, .feedback-item, [class*="feedback__item"], ' +
                '.comment-item, [class*="review-card"], [class*="review__item"]'
            );

            reviewContainers.forEach((container, index) => {
                if (index >= 10) return; // Get more initially, filter later

                const review = {};

                // Rating: look for star count or data attribute
                const ratingEl = container.querySelector('[class*="rating"], [class*="stars"], [data-rating]');
                if (ratingEl) {
                    // Try data attribute first
                    if (ratingEl.dataset.rating) {
                        review.rating = parseInt(ratingEl.dataset.rating) || 5;
                    } else {
                        // Count filled stars
                        const filled = ratingEl.querySelectorAll('[class*="filled"], [class*="active"], [fill="currentColor"]').length;
                        review.rating = filled > 0 ? filled : 5;
                    }
                } else {
                    review.rating = 5;
                }

                // Text: prioritize longer content blocks, avoid username containers
                let reviewText = '';
                const textSelectors = [
                    '.feedback__text',
                    '.feedback-text',
                    '[class*="comment__text"]',
                    '[class*="review-text"]',
                    '[class*="review__text"]',
                    'p.text',
                    '.text-content'
                ];

                for (const sel of textSelectors) {
                    const el = container.querySelector(sel);
                    if (el && el.textContent.trim().length > reviewText.length) {
                        reviewText = el.textContent.trim();
                    }
                }

                // Fallback: find the longest paragraph that looks like review content
                if (reviewText.length < 20) {
                    container.querySelectorAll('p, span, div').forEach(el => {
                        const text = el.textContent.trim();
                        // Skip if looks like metadata (date, user name, etc)
                        if (text.length > 30 &&
                            text.length < 1000 &&
                            !text.match(/^\\d{1,2}[./-]\\d{1,2}[./-]\\d{2,4}/) &&
                            !text.match(/^(Покупатель|Пользователь|Гость)/) &&
                            text.length > reviewText.length) {
                            reviewText = text;
                        }
                    });
                }

                review.text = reviewText.substring(0, 500);

                // Author: look for user/author names, avoid grabbing review text
                const authorSelectors = [
                    '.feedback__user-name',
                    '.user-name',
                    '[class*="author-name"]',
                    '[class*="reviewer-name"]'
                ];
                let author = 'Anonymous';
                for (const sel of authorSelectors) {
                    const el = container.querySelector(sel);
                    if (el && el.textContent.trim().length < 50) {
                        author = el.textContent.trim();
                        break;
                    }
                }
                review.author = author;

                // Date
                const dateEl = container.querySelector('[class*="date"], time, [class*="time"]');
                review.date = dateEl ? dateEl.textContent.trim() : '';

                // Only add if we have meaningful text
                if (review.text && review.text.length > 15) {
                    reviews.push(review);
                }
            });

            return reviews;
        }""")

        reviews = review_data if review_data else []

        # Sort by rating (best first) and limit to 5
        reviews = sorted(reviews, key=lambda x: x.get('rating', 0), reverse=True)[:5]

    except Exception as e:
        print(f"Error fetching reviews: {e}")

    return reviews


def fetch_wb_images_direct(product_id: str) -> List[str]:
    """
    Generate direct image URLs for WB product
    Fallback method if Playwright fails
    """
    vol = product_id[:4]
    part = product_id[:6]

    basket_num = (int(product_id) % 20) + 1
    host = f"basket-{basket_num:02d}.wbbasket.ru"

    images = []
    for i in range(1, 11):
        url = f"https://{host}/vol{vol}/part{part}/{product_id}/images/big/{i}.webp"
        images.append(url)

    return images


if __name__ == "__main__":
    import sys

    if len(sys.argv) < 2:
        print("Usage: python wb_fetcher_enhanced.py <WB_URL>")
        sys.exit(1)

    url = sys.argv[1]
    data = fetch_wb_product_enhanced(url, headless=True)

    if data:
        print(json.dumps(data, indent=2, ensure_ascii=False))
    else:
        print("Failed to fetch product data")
