import json
import logging
import re
from typing import Dict, Any, List, Optional
from langchain_core.messages import BaseMessage, HumanMessage, AIMessage

logger = logging.getLogger(__name__)

def _extract_text(content) -> str:
    """Extract plain text từ msg.content."""
    if isinstance(content, str):
        return content
    if isinstance(content, list):
        parts = []
        for item in content:
            if isinstance(item, dict) and item.get("type") == "text":
                parts.append(item.get("text", ""))
            elif isinstance(item, str):
                parts.append(item)
        return "\n".join(parts) if parts else str(content)
    return str(content or "")

_SKU_REGEX = re.compile(r"\b\d[A-Z0-9]{5,}(?:-[A-Z0-9]{2,}){0,2}\b", re.IGNORECASE)

def _dedupe_preserve_order(items: list[str]) -> list[str]:
    seen: set[str] = set()
    out: list[str] = []
    for raw in items:
        val = str(raw or "").upper().strip()
        if not val or val in seen:
            continue
        seen.add(val)
        out.append(val)
    return out

def _extract_skus_from_text(text: str | None) -> list[str]:
    if not text:
        return []
    matches = _SKU_REGEX.findall(text)
    return _dedupe_preserve_order([m for m in matches if m])

def _format_history(messages: list[BaseMessage], max_turns: int = 10) -> str:
    """Format recent messages cho context."""
    lines = []
    human_count = 0
    for msg in reversed(messages):
        if isinstance(msg, HumanMessage):
            lines.insert(0, f"Khách: {_extract_text(msg.content)[:500]}")
            human_count += 1
        elif isinstance(msg, AIMessage) and not (hasattr(msg, "tool_calls") and msg.tool_calls):
            lines.insert(0, f"Bot: {_extract_text(msg.content)[:500]}")
        if human_count >= max_turns:
            break
    return "\n".join(lines) if lines else "Chưa có lịch sử."

def _format_tool_result(tool_result: str | None) -> str:
    """Format kết quả từ tool thành text xịn cho Stylist."""
    if not tool_result:
        return ""
    try:
        parsed = json.loads(tool_result)
        if parsed.get("status") == "success":
            products = parsed.get("products", [])
            if products:
                dedup = {}
                for p in products:
                    sku = str(p.get("sku_code") or p.get("sku") or p.get("internal_ref_code") or "").upper().strip()
                    if sku and sku not in dedup:
                        dedup[sku] = p
                unique_products = list(dedup.values())

                lines = [f"✅ Tìm thấy {len(unique_products)} sản phẩm:"]
                for p in unique_products[:8]:
                    price = p.get("price", 0)
                    discount = p.get("discount", "")
                    line = f"- [{p.get('sku', '')}] {p.get('name', '')} | Giá: {price:,}đ"
                    if discount:
                        line += f" ({discount})"
                    if p.get("sizes"):
                        line += f" | Sizes: {p['sizes']}"
                    desc = (p.get("description") or "").strip()
                    if desc:
                        line += f"\n  📝 {desc[:200]}"

                    outfit = p.get("outfit_recommendations")
                    if outfit and isinstance(outfit, list):
                        outfit_lines = []
                        for o in outfit[:3]:
                            outfit_lines.append(
                                f"{o.get('role', 'match')}: {o.get('match_product_name')} ({o.get('match_product_code')})"
                            )
                        if outfit_lines:
                            line += f"\n  👗 outfit_recommendations: {', '.join(outfit_lines)}"
                    lines.append(line)
                return "\n".join(lines)
            return parsed.get("message", "Không tìm thấy sản phẩm phù hợp.")
        content = parsed.get("content") or parsed.get("message") or str(parsed)
        return str(content)[:800]
    except Exception:
        return (tool_result or "")[:500]

def parse_llm_json(text: str) -> Dict[str, Any]:
    """Senior Parser: Cleanly extract JSON from LLM response."""
    text = text.strip()
    if text.startswith('```json'): text = text[7:]
    if text.startswith('```'): text = text[3:]
    if text.endswith('```'): text = text[:-3]
    text = text.strip()
    
    start = text.find("{")
    end = text.rfind("}")
    if start != -1 and end != -1:
        text = text[start : end + 1]
    
    try:
        return json.loads(text)
    except json.JSONDecodeError:
        logger.error(f"❌ Failed to parse JSON: {text[:200]}")
        raise
