"""
Perception — Feed Content Analysis.

Structural analysis of the feed: detecting markers, carousels,
extracting post content. Zero-AI, pure structural parsing.

Extracted from bot_flow.py to enable isolated testing.
"""

import logging
import re
import xml.etree.ElementTree as ET

logger = logging.getLogger(__name__)


# ── Feed Presence Markers ──
# Resource IDs that confirm we're looking at a loaded feed post.
# Used by _wait_for_post_loaded and other wait loops.
FEED_MARKERS = [
    "row_feed_photo_profile_name",
    "row_feed_profile_header",
    "row_feed_photo_imageview",
    "clips_media_component",
    "clips_video_container",
    "clips_viewer_container",
    "clips_linear_layout_container",
    "zoomable_view_container",
    "feed_action_row",
    "carousel_viewpager",
]

# ── Carousel Detection ──
CAROUSEL_INDICATORS = [
    "com.instagram.android:id/carousel_page_indicator",
    "com.instagram.android:id/carousel_media_group",
    "com.instagram.android:id/carousel_viewpager",
]


def has_carousel_in_view(xml_dump: str) -> bool:
    """
    Checks if a carousel is present on screen based on standard Android UI identifiers.
    Handles 'carousel_page_indicator', 'carousel_media_group', and 'carousel_viewpager'.
    """
    return any(ind in xml_dump for ind in CAROUSEL_INDICATORS)


def extract_post_content(context_xml: str, device=None) -> dict:
    """
    Extracts meaningful content data from the current feed post's XML.
    This is the BOT'S EYES — what it actually "sees" about each post.

    Returns:
        {'username': str, 'description': str, 'caption': str, 'username_missing': bool}
    """
    result = {"username": "", "description": "", "caption": "", "username_missing": False}

    try:
        from GramAddict.core.telepathic_engine import TelepathicEngine

        telepath = TelepathicEngine.get_instance()

        # 1. Learn/extract post author dynamically
        # 🛡️ Structural Fast-Path: Prioritize deterministic IDs over AI guesses
        # Try structural ID fast-path first (100% deterministic)
        author_node = None
        try:
            root = ET.fromstring(context_xml)
            for node in root.iter("node"):
                res_id = node.attrib.get("resource-id", "")
                if "row_feed_photo_profile_name" in res_id or "clips_author_username" in res_id or "profile_header_name" in res_id:
                    author_node = {"original_attribs": node.attrib}
                    logger.debug(f"Identified author_node via structural ID: {res_id}")
                    break
        except Exception as e:
            logger.debug(f"XML parse error in author structural fast-path: {e}")

        # Fallback to Telepathic Engine if structural ID is missing
        if not author_node:
            author_node = telepath.find_best_node(
                context_xml, "post author username text (exclude bottom tabs)", min_confidence=0.75, device=device
            )
            logger.debug(f"Telepathic fallback for author_node: {author_node}")

        # 🛡️ Anti-Hallucination Guard: Ensure we actually found text.
        if author_node:
            attribs = author_node.get("original_attribs", {})
            text = attribs.get("text", "").strip()
            desc = attribs.get("content_desc", "").strip()
            
            if text:
                result["username"] = text
            elif desc:
                result["username"] = desc
            else:
                # If the VLM selected a container (like clips_author_info_component), 
                # extract text from its children.
                logger.debug("Author node lacks text/desc. Searching children for username...")
                bounds = attribs.get("bounds")
                if bounds:
                    try:
                        # Re-parse to find children within bounds
                        import re
                        match = re.match(r"\[(\d+),(\d+)\]\[(\d+),(\d+)\]", bounds)
                        if match:
                            l, t, r, b = map(int, match.groups())
                            
                            # Fallback: scan all nodes in XML and see if they are inside these bounds
                            possible_texts = []
                            possible_descs = []
                            for n in ET.fromstring(context_xml).iter("node"):
                                child_bounds = n.attrib.get("bounds")
                                child_text = n.attrib.get("text", "").strip()
                                child_desc = n.attrib.get("content-desc", "").strip()
                                
                                if child_bounds and (child_text or child_desc):
                                    cm = re.match(r"\[(\d+),(\d+)\]\[(\d+),(\d+)\]", child_bounds)
                                    if cm:
                                        cl, ct, cr, cb = map(int, cm.groups())
                                        # Check if child is strictly inside the container
                                        if cl >= l and ct >= t and cr <= r and cb <= b:
                                            if child_text:
                                                possible_texts.append(child_text)
                                            if child_desc and "Profile picture" not in child_desc:
                                                possible_descs.append(child_desc)
                            
                            if possible_texts:
                                result["username"] = possible_texts[0]
                                logger.debug(f"Extracted username '{result['username']}' from child node text.")
                            elif possible_descs:
                                result["username"] = possible_descs[0]
                                logger.debug(f"Extracted username '{result['username']}' from child node desc.")
                    except Exception as e:
                        logger.debug(f"Failed to extract username from children: {e}")

        # 2. Learn/extract post media description dynamically
        media_node = telepath.find_best_node(
            context_xml,
            "post media content (the actual image or video, exclude bottom tabs)",
            min_confidence=0.35,
            device=device,
        )
        if media_node and media_node.get("original_attribs", {}).get("content_desc"):
            result["description"] = media_node["original_attribs"]["content_desc"].strip()

        # 3. Visible caption text (heuristic fallback if node isn't explicitly found)
        # Search all nodes for text that contains the username to find the caption body
        root = ET.fromstring(context_xml)
        for node in root.iter("node"):
            text = node.attrib.get("text", "").strip()
            if result["username"] and len(text) > 20 and result["username"] in text:
                result["caption"] = text
                break

    except Exception as e:
        logger.warning(f"Error extracting post content autonomously: {e}")

    # REGRESSION FIX 2026-05-01: Flag unreliable data when username is empty
    if not result["username"]:
        result["username_missing"] = True
        logger.warning("⚠️ [PostDataExtraction] Username is empty — data may be unreliable.")

    return result


def _parse_number_from_text(text: str) -> int:
    """Extracts numeric value from strings like '1,234 likes', '1.5M views', 'Gefällt 12.345 Mal'."""
    text = text.lower()

    # Clean up purely thousands separators but keep decimals
    # If there is a 'm' or 'k', a period is usually a decimal (e.g. 1.5m).
    # If no 'm' or 'k', a period might be a German thousands separator (12.345).
    # We will let the regex handle decimals.

    # Remove commas (usually thousands separator in English)
    text = text.replace(",", "")

    # Find all numbers, potentially with k or m
    matches = re.findall(r"(\d+(?:\.\d+)?)\s*([km])?", text)
    if not matches:
        return 0

    best_val = 0
    for num_str, multiplier in matches:
        val = float(num_str)
        if multiplier == "k":
            val *= 1000
        elif multiplier == "m":
            val *= 1000000
        else:
            # If no multiplier, a period in num_str might be a German thousands separator
            if "." in num_str and val < 1000:
                # E.g. '12.345' became 12.345. Since no multiplier, it's actually 12345.
                # Heuristic: If it has 3 decimal places, it's a thousands separator.
                parts = num_str.split(".")
                if len(parts[1]) == 3:
                    val = float(num_str.replace(".", ""))

        best_val = max(best_val, int(val))

    return best_val


def has_feed_markers(xml_dump: str) -> bool:
    """Quick check: does this XML contain any feed presence markers?"""
    return any(marker in xml_dump for marker in FEED_MARKERS)
