"""
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. "
            "TUYỆT ĐỐI KHÔNG bao gồm các từ dư thừa như 'tìm cửa hàng', 'ở', 'tại', 'cho tôi'. "
            "Chỉ trích xuất ĐÚNG danh từ chỉ địa danh (VD: khách hỏi 'tìm cửa hàng ở vp' -> location: 'vp'). "
            "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:
    """
    AI PLANNER & RESPONDER - TÌM KIẾM CỬA HÀNG CANIFA

    1. LÚC GỌI TOOL (PLANNER):
    - Chỉ trích xuất đúng tên vị trí (VD: 'vp', 'Hà Nội', 'Cầu Giấy') vào tham số location. Không kèm từ thừa.
    - Nếu câu hỏi mơ hồ (không rõ khu vực/tỉnh/thành), HỎI LẠI khách bằng text thuần, KHÔNG gọi tool.

    2. LÚC TRẢ LỜI (RESPONDER):
    - Format kết quả tìm kiếm thành câu trả lời NGẮN GỌN (tối đa 3 cửa hàng gần nhất).
    - Mỗi cửa hàng ghi gọn 3 dòng: Tên + Địa chỉ + SĐT. Bỏ lịch trừ khi khách hỏi giờ mở cửa.
    - ⚠️ NẾU TOOL TRẢ VỀ CẢNH BÁO "KHÔNG có cửa hàng tại khu vực X": BẮT BUỘC phải nói rõ "Dạ, CANIFA hiện chưa có cửa hàng tại [X] ạ.", sau đó mới gợi ý các cửa hàng gần nhất (nếu có). KHÔNG được lơ đi cảnh báo này.
    - Ngôn ngữ thân thiện, tự nhiên. KHÔNG tự bịa địa chỉ/SĐT.
    """
    logger.info(f"🏪 [Store Search] Location: {location}")
    try:
        sr = get_db_connection()

        # ── Step -1: Clear conversational fillers (Cứu cánh khi AI ngu) ──
        raw_lower = location.lower().strip()
        fillers = [
            "tìm cửa hàng ở", "tìm cửa hàng tại", "cửa hàng ở", "cửa hàng tại",
            "có cửa hàng ở", "có cửa hàng tại", "cho địa chỉ ở", "địa chỉ ở",
            "địa chỉ tại", "ở khu vực", "khu vực", "ở", "tại", "tìm"
        ]
        for f in fillers:
            if raw_lower.startswith(f):
                raw_lower = raw_lower.replace(f, "", 1).strip()
            # Also handle if it's somewhere inside (less safe but covers cases like "mình muốn tìm cửa hàng ở vp")
            raw_lower = raw_lower.replace(f" {f} ", " ")

        # Clean up any leading/trailing spaces again
        raw_lower = raw_lower.strip()
        location = raw_lower  # Update location to cleaned version

        # ── Step 0: Expand viết tắt tỉnh ──
        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)
