"""
Tag Search Tool — LangChain @tool cho AI gọi.
AI sinh keywords + tags → Tool build SQL → 3 tầng cascade → Trả kết quả.

Architecture:
  CỐ ĐỊNH (luôn giữ): product_type + color + gender + price
  BIẾN ĐỔI (fallback):
    Tầng 1: CỐ ĐỊNH + keywords  (từ nguyên văn user)
    Tầng 2: CỐ ĐỊNH + tags      (AI suy luận → tags chung)
    Tầng 3: CHỈ CỐ ĐỊNH         (product_type + color + gender)
"""

import json
import logging
import time

from langchain_core.tools import tool
from pydantic import BaseModel, Field

from common.starrocks_connection import get_db_connection
from .product_mapping import SYNONYM_TO_DB, get_related_lines

logger = logging.getLogger(__name__)

TABLE_NAME = "test_db.magento_product_dimension_with_text_embedding"

SELECT_COLUMNS = """
    internal_ref_code,
    magento_ref_code,
    product_color_code,
    product_name,
    master_color,
    product_color_name,
    product_image_url_thumbnail,
    product_web_url,
    sale_price,
    original_price,
    COALESCE(discount_amount, 0) AS discount_amount,
    ROUND(CASE WHEN original_price > 0
        THEN ((original_price - sale_price) / original_price * 100)
        ELSE 0 END, 0) AS discount_percent,
    age_by_product,
    gender_by_product,
    product_line_vn,
    COALESCE(quantity_sold, 0) AS quantity_sold,
    COALESCE(is_new_product, 0) AS is_new_product,
    size_scale,
    description_text
"""


# ═══════════════════════════════════════════════
# Pydantic Schema — AI sẽ fill vào đây
# ═══════════════════════════════════════════════
class TagSearchInput(BaseModel):
    """Schema cho hybrid search: keywords (user) + tags (AI suy luận)."""

    model_config = {"extra": "forbid"}

    # ① KEYWORDS — từ NGUYÊN VĂN của user (ưu tiên cao, search TRƯỚC)
    keywords: list[str] = Field(
        default=[],
        description=(
            "Từ khoá NGUYÊN VĂN từ câu hỏi khách. "
            "VD: khách nói '30/4' → keywords=['30/4']. "
            "Khách nói 'cờ đỏ sao vàng' → keywords=['cờ đỏ sao vàng']. "
            "Khách nói 'cotton ống rộng' → keywords=['cotton', 'ống rộng']. "
            "Tối đa 2. Để [] nếu khách không nhắc gì đặc biệt."
        )
    )

    # ② TAGS — AI suy luận từ 4 TRỤC CỐ ĐỊNH (BẮT BUỘC có prefix!)
    tags: list[str] = Field(
        default=[],
        description=(
            "AI suy luận ý định khách → chọn từ 4 TRỤC CỐ ĐỊNH (BẮT BUỘC có prefix!): "
            "Trục 1 (occ:): occ:di_lam, occ:di_choi, occ:di_tiec, occ:di_hoc, occ:mac_nha, occ:the_thao, occ:di_bien, occ:du_lich, occ:da_ngoai, occ:di_ngu. "
            "Trục 2a (wthr:): wthr:mua_he, wthr:mua_dong, wthr:giao_mua, wthr:troi_mua, wthr:troi_nang. "
            "Trục 2b (func:): func:thoang_mat, func:giu_am, func:tham_hut, func:nhanh_kho, func:chong_uv, func:can_gio. "
            "Trục 3 (style:): style:thanh_lich, style:nang_dong, style:basic, style:ca_tinh, style:de_thuong, style:tre_trung, style:toi_gian, style:smart_casual. "
            "Trục 4 (fit:): fit:oversize, fit:slim, fit:regular, fit:wide_leg, fit:cropped, fit:relaxed. "
            "VD: 'đi tiệc' → tags=['occ:di_tiec']. 'mùa đông' → tags=['wthr:mua_dong', 'func:giu_am']. "
            "KHÔNG tự nghĩ tag mới! PHẢI giữ prefix! Tối đa 3."
        )
    )

    # ═══ CỐ ĐỊNH — Luôn giữ trong mọi tầng ═══
    product_line_vn: list[str] = Field(
        default=[],
        description=(
            "Dòng sản phẩm. CHÍNH XÁC lời user nói: 'áo phông', 'váy liền', 'đồ lót', 'quần jean'... "
            "Tool sẽ tự động chuẩn hoá từ đồng nghĩa (VD: 'áo thun' → 'Áo phông'). "
            "Nếu khách nói chung chung ('đồ mùa đông', 'đồ tập') hoặc không nhắc, để []. "
        ),
    )
    gender_by_product: str | None = Field(
        default=None,
        description="Giới tính. GIÁ TRỊ HỢP LỆ: women, men, boy, girl, unisex, newborn",
    )
    age_by_product: str | None = Field(
        default=None,
        description="Độ tuổi. GIÁ TRỊ HỢP LỆ: adult, kid, others",
    )
    master_color: str | None = Field(
        default=None,
        description=(
            "Màu sắc. Ghi CHÍNH XÁC từ khách nói: 'trắng', 'đen', 'đỏ'... "
            "VD: 'áo cờ đỏ sao vàng' → color='đỏ'."
        ),
    )
    price_min: int | None = Field(default=None, description="Giá thấp nhất (VND)")
    price_max: int | None = Field(default=None, description="Giá cao nhất (VND)")
    discount_min: int | None = Field(
        default=None, 
        description="% giảm giá TỐI THIỂU. VD: 'giảm 50%' → 50. 'hàng sale' → 1."
    )
    discount_max: int | None = Field(
        default=None, 
        description="% giảm giá TỐI ĐA. VD: 'giảm dưới 30%' → 30."
    )
    discovery_mode: str | None = Field(
        default=None,
        description="'new' = hàng mới, 'best_seller' = bán chạy. Chỉ dùng khi khách nói rõ.",
    )
    magento_ref_code: str | None = Field(
        default=None,
        description="Mã SKU cụ thể. Chỉ điền khi khách cung cấp.",
    )
    reasoning: str | None = Field(
        default=None,
        description=(
            "SUY LUẬN: Giải thích ngắn gọn TẠI SAO bạn chọn params này. "
            "VD: '2/9 = Quốc Khánh → áo đỏ đi chơi', 'khách muốn sịp mặc đi biển → giữ nguyên sịp, tag đi biển'. "
            "Viết 1-2 câu bằng tiếng Việt."
        ),
    )


# ═══════════════════════════════════════════════
# SQL Builder
# ═══════════════════════════════════════════════
def _build_fixed_clauses(req: TagSearchInput, params: list) -> list[str]:
    """Build các filter CỐ ĐỊNH (luôn giữ trong mọi tầng)."""
    clauses = []

    # Product line (list) — resolve synonym → search cột product_line_vn
    if req.product_line_vn:
        resolved_types = []
        for pt_raw in req.product_line_vn:
            pt = pt_raw.strip()
            if not pt:
                continue
            # Synonym resolve: "sịp" → "Quần lót", "áo thun" → "Áo phông"
            mapped = SYNONYM_TO_DB.get(pt.lower(), pt)
            # Related lines: "Quần lót" → ["Quần lót", "Quần lót đùi", "Quần lót tam giác"]
            related = get_related_lines(mapped)
            resolved_types.extend(related)
        resolved_types = list(dict.fromkeys(resolved_types))  # dedupe, keep order
        if resolved_types:
            in_placeholders = []
            like_clauses = []
            
            # Broad terms that need LIKE instead of exact IN match
            BROAD_TERMS = {"áo", "quần", "váy", "đồ", "bộ", "phụ kiện", "giày", "dép", "túi", "balo", "mũ", "nón", "tất"}
            
            for rt in resolved_types:
                if rt.lower() in BROAD_TERMS:
                    like_clauses.append("LOWER(product_line_vn) LIKE LOWER(%s)")
                    params.append(f"%{rt}%")
                else:
                    in_placeholders.append("%s")
                    params.append(rt)
            
            sub_clauses = []
            if in_placeholders:
                sub_clauses.append(f"LOWER(product_line_vn) IN ({', '.join(f'LOWER({p})' for p in in_placeholders)})")
            
            sub_clauses.extend(like_clauses)
            
            if sub_clauses:
                clauses.append("(" + " OR ".join(sub_clauses) + ")")
                
            logger.info("🏷️ [MAPPING] product_line_vn %s → resolved %s", req.product_line_vn, resolved_types)

    # Gender
    if req.gender_by_product:
        gender_lower = req.gender_by_product.lower().strip()
        if gender_lower in ("women", "nữ", "female"):
            gender_db = "female"
        elif gender_lower in ("men", "nam", "male"):
            gender_db = "male"
        else:
            gender_db = gender_lower

        if gender_db in ("female", "male"):
            params.append(gender_db)
            params.append("unisex")
            clauses.append(f"gender_by_product IN (%s, %s)")
        else:
            params.append(gender_db)
            clauses.append(f"gender_by_product = %s")

    # Age
    if req.age_by_product:
        age_lower = req.age_by_product.lower().strip()
        if age_lower in ("baby", "newborn"):
            params.append("kid")
            clauses.append(f"age_by_product = %s")
        else:
            params.append(age_lower)
            clauses.append(f"age_by_product = %s")

    # Color
    if req.master_color:
        c = req.master_color.lower().strip()
        params.append(f"%{c}%")
        params.append(f"%{c}%")
        clauses.append(f"(LOWER(master_color) LIKE %s OR LOWER(product_color_name) LIKE %s)")

    # Price
    if req.price_min is not None:
        params.append(req.price_min)
        clauses.append(f"sale_price >= %s")
    if req.price_max is not None:
        params.append(req.price_max)
        clauses.append(f"sale_price <= %s")

    # Discount
    if req.discount_min is not None:
        params.append(req.discount_min)
        # discount_percent is usually derived as ((original - sale) / original * 100)
        # Let's assume there is a discount_percent column, but looking at SELECT_COLUMNS, 
        # discount_percent is a calculated field. We should calculate it in the WHERE clause or use original_price > sale_price.
        # Actually in magento_product_dimension_with_text_embedding there probably IS some discount logic, but let's use:
        # WHERE original_price > 0 AND ((original_price - sale_price) / original_price * 100) >= X
        clauses.append(f"(original_price > 0 AND ((original_price - sale_price) / original_price * 100) >= %s)")
    if req.discount_max is not None:
        params.append(req.discount_max)
        clauses.append(f"(original_price > 0 AND ((original_price - sale_price) / original_price * 100) <= %s)")

    # Discovery mode
    if req.discovery_mode:
        mode = req.discovery_mode.lower().strip()
        if mode == "new":
            clauses.append("is_new_product = 1")
        elif mode == "best_seller":
            clauses.append("quantity_sold > 0")

    return clauses


# ═══════════════════════════════════════════════
# Tag → Vietnamese search text (cho LIKE query)
# ═══════════════════════════════════════════════
TAG_TO_SEARCH_TEXT: dict[str, str] = {
    # Trục 1 — Hoàn cảnh & Dịp
    "occ:di_lam": "đi làm",
    "occ:di_choi": "đi chơi",
    "occ:di_tiec": "đi tiệc",
    "occ:di_hoc": "đi học",
    "occ:mac_nha": "mặc nhà",
    "occ:the_thao": "thể thao",
    "occ:di_bien": "đi biển",
    "occ:du_lich": "du lịch",
    "occ:da_ngoai": "dã ngoại",
    "occ:di_ngu": "đi ngủ",
    # Trục 2a — Thời tiết
    "wthr:mua_he": "mùa hè",
    "wthr:mua_dong": "mùa đông",
    "wthr:giao_mua": "giao mùa",
    "wthr:troi_mua": "trời mưa",
    "wthr:troi_nang": "trời nắng",
    # Trục 2b — Tính năng
    "func:thoang_mat": "thoáng mát",
    "func:giu_am": "giữ ấm",
    "func:tham_hut": "thấm hút",
    "func:nhanh_kho": "nhanh khô",
    "func:chong_uv": "chống uv",
    "func:can_gio": "cản gió",
    # Trục 3 — Phong cách
    "style:thanh_lich": "thanh lịch",
    "style:nang_dong": "năng động",
    "style:basic": "basic",
    "style:ca_tinh": "cá tính",
    "style:de_thuong": "dễ thương",
    "style:tre_trung": "trẻ trung",
    "style:toi_gian": "tối giản",
    "style:smart_casual": "smart casual",
    # Trục 4 — Dáng
    "fit:oversize": "oversize",
    "fit:slim": "slim",
    "fit:regular": "regular",
    "fit:wide_leg": "ống rộng",
    "fit:cropped": "cropped",
    "fit:relaxed": "relaxed",
}


def _resolve_tag(tag: str) -> str:
    """Chuyển prefixed tag → Vietnamese text cho SQL LIKE.
    VD: 'occ:di_tiec' → 'đi tiệc', 'func:giu_am' → 'giữ ấm'.
    Nếu không có trong mapping (tag cũ format) → giữ nguyên.
    """
    return TAG_TO_SEARCH_TEXT.get(tag.strip().lower(), tag)


def _build_search_clause(search_terms: list[str], params: list, resolve_tags: bool = False) -> str:
    """Build OR clause cho keywords hoặc tags, search trong description_text và product_name.
    Tách các từ trong mỗi term bằng khoảng trắng và áp dụng toán tử AND để tìm kiếm rộng hơn.
    """
    term_clauses = []
    for term in search_terms:
        t = _resolve_tag(term) if resolve_tags else term.strip().lower()
        if not t:
            continue
            
        words = t.split()
        if not words:
            continue
            
        word_clauses = []
        for word in words:
            params.append(f"%{word}%")
            params.append(f"%{word}%")
            word_clauses.append(f"(LOWER(description_text) LIKE %s OR LOWER(product_name) LIKE %s)")
            
        term_clauses.append(f"({' AND '.join(word_clauses)})")
        
    if term_clauses:
        return f"({' OR '.join(term_clauses)})"
    return ""


def _build_full_query(fixed_clauses: list[str], search_clause: str | None) -> str:
    """Combine fixed + search clauses thành SQL hoàn chỉnh."""
    all_clauses = list(fixed_clauses)
    if search_clause:
        all_clauses.append(search_clause)

    where = " AND ".join(all_clauses) if all_clauses else "1=1"
    return f"""
    SELECT {SELECT_COLUMNS}
    FROM {TABLE_NAME}
    WHERE {where}
    ORDER BY quantity_sold DESC NULLS LAST, sale_price ASC
    LIMIT 20
    """


# ═══════════════════════════════════════════════
# 3-Tier Cascading Search
# ═══════════════════════════════════════════════
async def _cascading_search(req: TagSearchInput, db) -> tuple[list, int]:
    """
    3 tầng fallback:
      Tầng 1: CỐ ĐỊNH + keywords  (từ nguyên văn user)
      Tầng 2: CỐ ĐỊNH + tags      (AI suy luận → tags chung)
      Tầng 3: CHỈ CỐ ĐỊNH         (product_type + color + gender)

    Returns: (products, tier_matched)
    """

    # ---- Tầng 1: CỐ ĐỊNH + KEYWORDS ----
    if req.keywords:
        params = []
        fixed = _build_fixed_clauses(req, params)
        search = _build_search_clause(req.keywords, params)
        if search:
            sql = _build_full_query(fixed, search)
            products = await db.execute_query_async(sql, params=tuple(params))
            if products:
                logger.info("🎯 Tầng 1 (keywords) match! %d kết quả", len(products))
                return products, 1

    # ---- Tầng 2: CỐ ĐỊNH + TAGS ----
    if req.tags:
        params = []
        fixed = _build_fixed_clauses(req, params)
        search = _build_search_clause(req.tags, params, resolve_tags=True)
        if search:
            sql = _build_full_query(fixed, search)
            products = await db.execute_query_async(sql, params=tuple(params))
            if products:
                logger.info("🎯 Tầng 2 (tags chung) match! %d kết quả", len(products))
                return products, 2

    # ---- Tầng 3: CHỈ CỐ ĐỊNH ----
    params = []
    fixed = _build_fixed_clauses(req, params)
    sql = _build_full_query(fixed, None)
    products = await db.execute_query_async(sql, params=tuple(params))
    if products:
        logger.info("🎯 Tầng 3 (chỉ cố định) match! %d kết quả", len(products))
        return products, 3
    logger.info("🎯 Tầng 3 (chỉ cố định) match! 0 kết quả")

    # ---- Tầng 4: DROP GENDER, chỉ giữ product_line ----
    # VD: "sịp nam" → gender=men returns 0 → try again without gender
    if req.product_line_vn and req.gender_by_product:
        logger.info("🔄 Tầng 4: thử drop gender '%s' để tìm rộng hơn...", req.gender_by_product)
        saved_gender = req.gender_by_product
        req.gender_by_product = None  # drop gender
        params = []
        fixed = _build_fixed_clauses(req, params)
        sql = _build_full_query(fixed, None)
        products = await db.execute_query_async(sql, params=tuple(params))
        req.gender_by_product = saved_gender  # restore
        if products:
            logger.info("🎯 Tầng 4 (drop gender) match! %d kết quả", len(products))
            return products, 4

    return [], 3


def _format_products(products: list) -> list[dict]:
    """Format output cho AI đọc."""
    formatted = []
    for p in products[:15]:
        sale = float(p.get("sale_price") or 0)
        orig = float(p.get("original_price") or 0)
        has_discount = sale < orig and orig > 0
        disc_pct = int(p.get("discount_percent") or 0)
        formatted.append({
            "sku": p.get("magento_ref_code", ""),
            "name": p.get("product_name", ""),
            "price": int(sale),
            "original_price": int(orig),
            "discount": f"-{disc_pct}%" if has_discount else None,
            "color": p.get("master_color", ""),
            "gender": p.get("gender_by_product", ""),
            "product_line": p.get("product_line_vn", ""),
            "image": p.get("product_image_url_thumbnail", ""),
            "url": p.get("product_web_url", ""),
            "sizes": p.get("size_scale", ""),
        })
    return formatted


# ═══════════════════════════════════════════════
# SKU Lookup (đặc biệt, bypass cascade)
# ═══════════════════════════════════════════════
def _build_sku_query(code: str) -> tuple[str, list]:
    """Build query tìm theo mã SKU."""
    code = code.strip().upper()
    sql = f"""
    SELECT {SELECT_COLUMNS}
    FROM {TABLE_NAME}
    WHERE (UPPER(magento_ref_code) = %s
           OR UPPER(internal_ref_code) = %s
           OR UPPER(magento_ref_code) LIKE %s)
    ORDER BY quantity_sold DESC NULLS LAST
    LIMIT 20
    """
    return sql, [code, code, f"{code}%"]


# ═══════════════════════════════════════════════
# Tool Entry Point
# ═══════════════════════════════════════════════
@tool(args_schema=TagSearchInput)
async def tag_search_tool(
    keywords: list[str] | None = None,
    tags: list[str] | None = None,
    product_line_vn: list[str] | None = None,
    gender_by_product: str | None = None,
    age_by_product: str | None = None,
    master_color: str | None = None,
    price_min: int | None = None,
    price_max: int | None = None,
    discount_min: int | None = None,
    discount_max: int | None = None,
    discovery_mode: str | None = None,
    magento_ref_code: str | None = None,
    reasoning: str | None = None,
) -> str:
    """
    Tìm kiếm sản phẩm CANIFA.
    Ưu tiên keywords (từ user) trước, nếu không có thì dùng tags (AI suy luận).
    Hệ thống tự động fallback qua 3 tầng.
    """
    start = time.time()

    req = TagSearchInput(
        keywords=keywords or [],
        tags=tags or [],
        product_line_vn=product_line_vn or [],
        gender_by_product=gender_by_product,
        age_by_product=age_by_product,
        master_color=master_color,
        price_min=price_min,
        price_max=price_max,
        discount_min=discount_min,
        discount_max=discount_max,
        discovery_mode=discovery_mode,
        magento_ref_code=magento_ref_code,
    )

    db = get_db_connection()

    try:
        # SKU lookup (bypass cascade)
        if req.magento_ref_code:
            sql, params = _build_sku_query(req.magento_ref_code)
            products = await db.execute_query_async(sql, params=tuple(params))
            tier = 0
        else:
            # 3-tier cascading search
            products, tier = await _cascading_search(req, db)

        elapsed_ms = round((time.time() - start) * 1000, 2)

        logger.info(
            "🏷️ [SEARCH] keywords=%s, tags=%s, type=%s, color=%s, gender=%s | tier=%d, results=%d, time=%.2fms",
            keywords, tags, product_line_vn, master_color, gender_by_product,
            tier, len(products), elapsed_ms,
        )

        formatted = _format_products(products)

        return json.dumps({
            "status": "success",
            "count": len(products),
            "tier": tier,
            "elapsed_ms": elapsed_ms,
            "reasoning": reasoning or "",
            "keywords_used": keywords or [],
            "tags_used": tags or [],
            "products": formatted,
        }, ensure_ascii=False, default=str)

    except Exception as e:
        logger.error("❌ Search tool error: %s", e)
        return json.dumps({"status": "error", "message": str(e)})
