"""
Store Search Tool — Tìm cửa hàng CANIFA theo địa điểm
======================================================
- Expand viết tắt tỉnh/thành (63 tỉnh VN) trước khi query
- 2-step search: strict token match → reverse LIKE fallback
- Format kết quả rõ ràng cho LLM
"""

import logging
from typing import Any

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

from common.starrocks_connection import get_db_connection

logger = logging.getLogger(__name__)

STORE_TABLE = "shared_source.chatbot_rsa_store_schedule_with_text_embedding"


# ═══════════════════════════════════════════════════════════════
# PROVINCE ALIAS MAP — 63 tỉnh/thành Việt Nam
# Format: "Tên đầy đủ (DB)": ["viết tắt", "không dấu", "slang"]
# ═══════════════════════════════════════════════════════════════
_PROVINCE_ALIASES: dict[str, list[str]] = {
    # ── 5 Thành phố trực thuộc TW ──
    "Hồ Chí Minh":      ["hcm", "tphcm", "tp hcm", "sg", "sài gòn", "saigon", "ho chi minh"],
    "Hà Nội":           ["hn", "hanoi", "ha noi"],
    "Hải Phòng":        ["hp", "hai phong"],
    "Đà Nẵng":          ["dn", "đn", "da nang"],
    "Cần Thơ":          ["ct", "can tho"],

    # ── Bắc Bộ ──
    "Hà Giang":         ["hg", "ha giang"],
    "Cao Bằng":         ["cb", "cao bang"],
    "Bắc Giang":        ["bg", "bac giang"],
    "Bắc Kạn":          ["bk", "bac kan"],
    "Bắc Ninh":         ["bn", "bac ninh"],
    "Điện Biên":        ["db", "dien bien"],
    "Hòa Bình":         ["hb", "hoa binh"],
    "Hưng Yên":         ["hy", "hung yen"],
    "Hải Dương":        ["hd", "hai duong"],
    "Hà Nam":           ["hnam", "ha nam"],
    "Lai Châu":         ["lch", "lai chau"],
    "Lào Cai":          ["lc", "lao cai"],
    "Lạng Sơn":         ["ls", "lang son"],
    "Nam Định":         ["nd", "nam dinh"],
    "Ninh Bình":        ["nb", "ninh binh"],
    "Phú Thọ":          ["pt", "phu tho"],
    "Quảng Ninh":       ["qn", "quang ninh"],
    "Sơn La":           ["sl", "son la"],
    "Thái Bình":        ["tb", "thai binh"],
    "Thái Nguyên":      ["tn", "thai nguyen"],
    "Tuyên Quang":      ["tq", "tuyen quang"],
    "Vĩnh Phúc":        ["vp", "vinh phuc"],
    "Yên Bái":          ["yb", "yen bai"],

    # ── Bắc Trung Bộ ──
    "Thanh Hoá":        ["th", "thanh hoa"],
    "Nghệ An":          ["na", "nghe an"],
    "Hà Tĩnh":          ["ht", "ha tinh"],
    "Quảng Bình":       ["qb", "quang binh"],
    "Quảng Trị":        ["qt", "quang tri"],
    "Thừa Thiên Huế":   ["tth", "hue", "huế", "thua thien hue"],

    # ── Nam Trung Bộ ──
    "Quảng Nam":        ["qnam", "quang nam"],
    "Quảng Ngãi":       ["qng", "quang ngai"],
    "Bình Định":        ["bdi", "binh dinh"],
    "Phú Yên":          ["py", "phu yen"],
    "Khánh Hòa":        ["kh", "nt", "khanh hoa", "nha trang"],
    "Bình Thuận":       ["bth", "binh thuan", "phan thiet"],
    "Ninh Thuận":       ["nth", "ninh thuan"],

    # ── Tây Nguyên ──
    "Gia Lai":          ["gl", "gia lai"],
    "Kon Tum":          ["kt", "kon tum"],
    "Đắk Lắk":         ["dlk", "dak lak"],
    "Đắk Nông":        ["dkn", "dak nong"],
    "Lâm Đồng":        ["ld", "lam dong", "da lat", "đà lạt", "dalat"],

    # ── Đông Nam Bộ ──
    "Bình Dương":       ["bd", "binh duong"],
    "Bình Phước":       ["bp", "binh phuoc"],
    "Đồng Nai":         ["dnai", "dong nai"],
    "Tây Ninh":         ["tnin", "tay ninh"],
    "Bà Rịa – Vũng Tàu": ["brvt", "vt", "vung tau", "ba ria"],

    # ── Tây Nam Bộ (ĐBSCL) ──
    "An Giang":         ["ag", "an giang"],
    "Bạc Liêu":        ["bl", "bac lieu"],
    "Bến Tre":          ["bt", "ben tre"],
    "Cà Mau":           ["cm", "ca mau"],
    "Đồng Tháp":        ["dt", "dong thap"],
    "Hậu Giang":        ["hgi", "hau giang"],
    "Kiên Giang":       ["kg", "kien giang", "phu quoc", "phú quốc"],
    "Long An":          ["la", "long an"],
    "Sóc Trăng":        ["st", "soc trang"],
    "Tiền Giang":       ["tg", "tien giang"],
    "Trà Vinh":         ["tv", "tvi", "tra vinh"],
    "Vĩnh Long":        ["vl", "vinh long"],
}

# Build reverse lookup: alias → province name (auto-generated)
PROVINCE_ABBR: dict[str, str] = {}
for _province, _aliases in _PROVINCE_ALIASES.items():
    for _alias in _aliases:
        PROVINCE_ABBR[_alias] = _province


# ═══════════════════════════════════════════════════════════════
# TOOL DEFINITION
# ═══════════════════════════════════════════════════════════════

class StoreSearchInput(BaseModel):
    location: str = Field(
        description=(
            "Tên quận/huyện/tỉnh/thành phố hoặc địa chỉ cụ thể "
            "mà khách hàng muốn tìm cửa hàng CANIFA. "
            "VD: 'Hoàng Mai', 'Cầu Giấy', 'Đà Nẵng', 'Vincom Bà Triệu'."
        )
    )


@tool("canifa_store_search", args_schema=StoreSearchInput)
async def canifa_store_search(location: str) -> str:
    """
    Tìm kiếm cửa hàng CANIFA theo địa điểm/khu vực.
    Sử dụng khi khách hàng hỏi về cửa hàng tại một khu vực cụ thể.
    """
    logger.info(f"🏪 [Store Search] Location: {location}")
    try:
        sr = get_db_connection()

        # ── Step 0: Expand viết tắt tỉnh ──
        raw_lower = location.lower().strip()
        if raw_lower in PROVINCE_ABBR:
            expanded = PROVINCE_ABBR[raw_lower]
            logger.info(f"📝 Alias expanded: '{raw_lower}' → '{expanded}'")
            location = expanded

        # ── Step 0.5: Clean prefix ──
        clean = location.lower().strip()
        for prefix in ["quận ", "huyện ", "tỉnh ", "thành phố ", "tp. ", "tp "]:
            clean = clean.replace(prefix, "")
        clean = clean.strip()

        words = [w for w in clean.replace(",", " ").split() if w.strip()]

        if not words:
            return (
                "Vui lòng cho em biết khu vực bạn muốn tìm cửa hàng CANIFA "
                "(ví dụ: Hoàng Mai, Cầu Giấy, Đà Nẵng...)."
            )

        text_col = "LOWER(concat_ws(' ', store_name, address, city, state))"

        # ═══════════════════════════════════════════════════════════
        # SINGLE QUERY — Phrase Sliding Window
        #
        # Giữ nguyên THỨ TỰ từ, match CỤM LIÊN TIẾP trong DB.
        # "nội bài đông anh" (4 words) → sinh các cụm:
        #   len=4: "nội bài đông anh"
        #   len=3: "nội bài đông", "bài đông anh"
        #   len=2: "nội bài", "bài đông", "đông anh"
        #
        # Score = độ dài cụm match dài nhất.
        # "đông anh" match → score 2. Stores ở Hà Đông (chỉ match "đông") → 0 → filtered.
        # ═══════════════════════════════════════════════════════════

        if len(words) == 1:
            # ── Single word: simple LIKE ──
            sql = f"""
            SELECT store_name, address, city, state, phone_number,
                   schedule_name, time_open_today, time_close_today,
                   1 AS match_score
            FROM {STORE_TABLE}
            WHERE {text_col} LIKE '%{words[0]}%'
            ORDER BY state, city, store_name
            LIMIT 20
            """
        else:
            # ── Multi-word: consecutive phrase matching ──
            # Sinh tất cả cụm liên tiếp ≥ 2 từ, ordered by length DESC
            phrases: list[tuple[str, int]] = []
            for length in range(len(words), 1, -1):
                for start in range(len(words) - length + 1):
                    phrase = " ".join(words[start:start + length])
                    phrases.append((phrase, length))

            # Build CASE WHEN → score = longest matching phrase
            case_when = " ".join(
                f"WHEN {text_col} LIKE '%{p}%' THEN {score}"
                for p, score in phrases
            )
            score_expr = f"CASE {case_when} ELSE 0 END"

            # WHERE: OR tất cả phrases (ít nhất 1 cụm ≥ 2 từ phải match)
            or_conds = " OR ".join(
                f"{text_col} LIKE '%{p}%'" for p, _ in phrases
            )

            sql = f"""
            SELECT store_name, address, city, state, phone_number,
                   schedule_name, time_open_today, time_close_today,
                   ({score_expr}) AS match_score
            FROM {STORE_TABLE}
            WHERE ({or_conds})
            ORDER BY match_score DESC, state, city, store_name
            LIMIT 20
            """

        results = await sr.execute_query_async(sql)
        logger.info(
            f"📊 Phrase search: {len(results)} stores, words={words}"
        )

        # ═══════════════════════════════════════════════════════════
        # FALLBACK — Reverse LIKE (chỉ khi phrase search = 0)
        # ═══════════════════════════════════════════════════════════
        if not results and len(words) >= 2:
            city_stripped = (
                "LOWER(TRIM(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE("
                "city, 'Quận ', ''), 'Huyện ', ''), 'Thành phố ', ''), "
                "'Thị xã ', ''), 'TP. ', '')))"
            )
            state_lower = "LOWER(TRIM(state))"
            fallback_sql = f"""
            SELECT store_name, address, city, state, phone_number,
                   schedule_name, time_open_today, time_close_today,
                   1 AS match_score
            FROM {STORE_TABLE}
            WHERE (LOCATE({city_stripped}, '{clean}') > 0
                   AND LENGTH({city_stripped}) > 1)
               OR (LOCATE({state_lower}, '{clean}') > 0
                   AND LENGTH({state_lower}) > 1)
            ORDER BY state, city, store_name
            LIMIT 20
            """
            results = await sr.execute_query_async(fallback_sql)
            logger.info(f"📊 Reverse-LIKE fallback: {len(results)} stores")

        logger.info(
            f"📊 Store search: {len(results)} stores for '{location}'"
        )

        if not results:
            return (
                f"Không tìm thấy cửa hàng CANIFA tại khu vực '{location}'. "
                f"Khách hàng có thể liên hệ hotline 1800 6061 "
                f"để được hỗ trợ tìm cửa hàng gần nhất."
            )

        # ── Format kết quả cho LLM ──
        return _format_results(results, location, words)

    except Exception as e:
        logger.error(f"❌ Error in canifa_store_search: {e}")
        return (
            "Tôi đang gặp khó khăn khi tìm kiếm cửa hàng. "
            "Bạn có thể liên hệ hotline 1800 6061 để được hỗ trợ."
        )


def _format_results(
    results: list[dict[str, Any]],
    location: str,
    words: list[str],
) -> str:
    """Format store search results with enriched location context."""

    # ── 1. Phân tích khu vực thực tế từ kết quả DB ──
    states: set[str] = set()
    cities: set[str] = set()
    all_text_lower = ""
    for r in results:
        city = r.get("city", "")
        state = r.get("state", "")
        if state:
            states.add(state)
        if city:
            cities.add(city)
        all_text_lower += (
            f" {r.get('store_name','')} {r.get('address','')}"
            f" {city} {state}"
        ).lower()

    # ── 2. Tìm cụm từ user nhập mà KHÔNG xuất hiện trong kết quả ──
    # Chỉ match cụm >= 2 từ để tránh false positive
    # ("bình" xuất hiện trong "Bình Phú" ≠ "Bình Xuyên")
    matched_indices: set[int] = set()

    # Bước 2a: Match cụm >= 2 từ (chính xác)
    for length in range(len(words), 1, -1):
        for start in range(len(words) - length + 1):
            if any(i in matched_indices for i in range(start, start + length)):
                continue
            phrase = " ".join(words[start:start + length])
            if phrase in all_text_lower:
                matched_indices.update(range(start, start + length))

    # Bước 2b: Chỉ match single word NẾU nó là từ duy nhất
    if len(words) == 1 and words[0] in all_text_lower:
        matched_indices.add(0)

    # Gom các từ chưa match thành cụm liên tiếp
    unmatched_phrases: list[str] = []
    i = 0
    while i < len(words):
        if i not in matched_indices:
            start = i
            while i < len(words) and i not in matched_indices:
                i += 1
            unmatched_phrases.append(" ".join(words[start:i]).title())
        else:
            i += 1

    # ── 3. Build header rõ ràng ──
    state_str = ", ".join(sorted(states)) if states else ""
    city_str = " / ".join(sorted(cities)) if cities else ""

    header_parts = [f"Tìm thấy {len(results)} cửa hàng CANIFA"]
    if state_str and city_str:
        header_parts.append(f"tại {city_str} (tỉnh/thành phố {state_str})")
    elif state_str:
        header_parts.append(f"tại tỉnh/thành phố {state_str}")
    else:
        header_parts.append(f"tại khu vực '{location}'")
    header = " ".join(header_parts) + ":"

    # Ghi rõ phần KHÔNG match + hướng dẫn bot cách trả lời
    if unmatched_phrases:
        for phrase in unmatched_phrases:
            header += (
                f"\n⚠️ CANIFA hiện KHÔNG có cửa hàng tại khu vực "
                f"'{phrase}'. Hãy thông báo rõ cho khách hàng rằng "
                f"'{phrase}' không có cửa hàng CANIFA, và gợi ý "
                f"các cửa hàng gần nhất bên dưới."
            )

    # ── 4. Format từng store ──
    # Khi có unmatched → chỉ hiển thị tối đa 5 store gần nhất
    display_results = results[:5] if unmatched_phrases else results

    lines = []
    for r in display_results:
        name     = r.get("store_name", "")
        addr     = r.get("address", "")
        city     = r.get("city", "")
        state    = r.get("state", "")
        phone    = r.get("phone_number", "")
        schedule = r.get("schedule_name", "")
        t_open   = r.get("time_open_today", "")
        t_close  = r.get("time_close_today", "")

        parts = [f"🏪 {name}"]
        addr_full = ", ".join(filter(None, [addr, city, state]))
        parts.append(f"   📍 Địa chỉ: {addr_full}")
        parts.append(f"   📞 ĐT: {phone}")
        sched_str = f"   🕐 Lịch: {schedule}"
        if t_open and t_close:
            sched_str += f" (Hôm nay: {t_open}-{t_close})"
        parts.append(sched_str)

        lines.append("\n".join(parts))

    return header + "\n\n" + "\n\n".join(lines)
