"""
Chatbot service — rule-based with optional Claude AI upgrade.

Rule-based search order:
  1. Curated ChatbotKnowledge entries (keyword match)
  2. Site FAQs (keyword match on question + answer)
  3. Property listings (location / type / feature match)
  4. Sales updates / blog (keyword match in title + excerpt + body)
  5. Hard-coded intent buckets (greetings, contact, etc.)
  6. Generic fallback

Anthropic mode (when ANTHROPIC_API_KEY is set):
  - Full context: all properties, all FAQs, KB, recent blog posts
"""
from django.conf import settings
from django.utils.html import strip_tags
from apps.core.models import SiteSetting, FAQ
from apps.properties.models import Property
from apps.sales_updates.models import SalesUpdate
from .models import ChatbotKnowledge


# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------

def _keywords(text):
    """Meaningful words (>3 chars) from a string, lowercased."""
    return {w.lower() for w in text.split() if len(w) > 3}


def _score(query_words, target_text):
    """Count how many query words appear in target_text."""
    target = target_text.lower()
    return sum(1 for w in query_words if w in target)


# ---------------------------------------------------------------------------
# Context builder for Anthropic mode
# ---------------------------------------------------------------------------

def _build_context():
    site = SiteSetting.get()
    properties = Property.objects.filter(is_published=True).select_related('location', 'category')[:50]
    faqs = FAQ.objects.filter(is_published=True)[:30]
    kb = ChatbotKnowledge.objects.filter(is_active=True)[:30]
    updates = SalesUpdate.objects.filter(is_published=True).order_by('-publish_at')[:8]

    parts = [
        f"You are {site.chatbot_name}, the helpful AI assistant for {site.site_name}, "
        f"a real estate company in Nigeria. Be warm, professional, and concise.",
        "",
        f"Contact: phone {site.phone}, email {site.email}, WhatsApp {site.whatsapp_number}.",
        f"Address: {site.address}",
        "",
        "Your role:",
        "- Help visitors find properties (houses, lands, rentals, short-lets).",
        "- Answer questions about pricing, locations, documents, and financing.",
        "- Draw on the FAQs, property listings, and articles below to give specific answers.",
        "- Suggest scheduling a viewing or speaking with an agent for serious inquiries.",
        "- Never invent property details that were not given to you.",
        "",
    ]

    # Properties
    if properties:
        parts.append("Current property listings:")
        for p in properties:
            line = (
                f"- {p.title} | {p.get_listing_type_display()} | {p.location} "
                f"| {p.price_display}"
            )
            if p.bedrooms:
                line += f" | {p.bedrooms} bed"
            if p.bathrooms:
                line += f" | {p.bathrooms} bath"
            if p.plot_size:
                line += f" | {p.plot_size}"
            if p.title_documents:
                line += f" | Docs: {p.title_documents}"
            if p.feature_list:
                line += f" | Features: {', '.join(p.feature_list[:5])}"
            line += f" | /properties/{p.slug}/"
            parts.append(line)
    else:
        parts.append("No properties currently listed — direct visitors to /properties/")

    # FAQs
    if faqs:
        parts.append("")
        parts.append("Website FAQs:")
        for f in faqs:
            parts.append(f"Q: {f.question}\nA: {f.answer}")

    # Curated KB
    if kb:
        parts.append("")
        parts.append("Additional knowledge:")
        for k in kb:
            parts.append(f"Q: {k.question}\nA: {k.answer}")

    # Blog / news
    if updates:
        parts.append("")
        parts.append("Recent articles and news:")
        for u in updates:
            excerpt = u.excerpt or strip_tags(u.content)[:200]
            parts.append(f"- {u.title}: {excerpt}")

    parts.append("")
    parts.append(
        "When a visitor shows serious interest, end with: "
        "'Would you like me to schedule a viewing or have an agent call you?'"
    )
    return "\n".join(parts)


# ---------------------------------------------------------------------------
# Anthropic (Claude) reply
# ---------------------------------------------------------------------------

def _anthropic_reply(history, user_message):
    import anthropic
    client = anthropic.Anthropic(api_key=settings.ANTHROPIC_API_KEY)

    messages = []
    for m in history[-10:]:
        messages.append({"role": m.role, "content": m.content})
    messages.append({"role": "user", "content": user_message})

    resp = client.messages.create(
        model="claude-haiku-4-5-20251001",
        max_tokens=600,
        system=_build_context(),
        messages=messages,
    )
    out = [block.text for block in resp.content if hasattr(block, "text")]
    return "\n".join(out).strip() or "Could you rephrase that?"


# ---------------------------------------------------------------------------
# Rule-based search functions
# ---------------------------------------------------------------------------

def _search_faqs(query_words):
    """Return the best-matching FAQ answer, or None (requires score >= 2)."""
    best_score, best_answer = 0, None
    for faq in FAQ.objects.filter(is_published=True):
        score = _score(query_words, faq.question + " " + faq.answer)
        if score > best_score:
            best_score, best_answer = score, faq.answer
    return best_answer if best_score >= 2 else None


def _search_properties(query_words, msg):
    """Return a short reply listing matching properties, or None."""
    listing_type = None
    if any(w in msg for w in ["shortlet", "short let", "short-let", "airbnb"]):
        listing_type = "shortlet"
    elif any(w in msg for w in ["lease"]):
        listing_type = "lease"
    elif any(w in msg for w in ["rent", "rental", "renting"]):
        listing_type = "rent"
    elif any(w in msg for w in ["buy", "purchase", "sale", "sell", "for sale"]):
        listing_type = "sale"

    qs = Property.objects.filter(is_published=True).select_related("location", "category")
    if listing_type:
        qs = qs.filter(listing_type=listing_type)

    scored = []
    for p in qs[:60]:
        search_text = " ".join([
            p.title,
            str(p.location),
            p.address,
            p.short_description,
            p.features,
            p.category.name if p.category else "",
            p.title_documents,
        ])
        score = _score(query_words, search_text)
        if score > 0:
            scored.append((score, p))

    if not scored:
        return None

    scored.sort(key=lambda x: -x[0])
    top = scored[:3]
    lines = ["Here are some matching properties:"]
    for _, p in top:
        lines.append(
            f"- **{p.title}** ({p.get_listing_type_display()}) — "
            f"{p.location} — {p.price_display} — "
            f"[View details](/properties/{p.slug}/)"
        )
    lines.append("\nWould you like more details or to schedule a viewing for any of these?")
    return "\n".join(lines)


def _search_updates(query_words):
    """Return a relevant blog/update excerpt, or None (requires score >= 2)."""
    best_score, best = 0, None
    for u in SalesUpdate.objects.filter(is_published=True).order_by("-publish_at")[:20]:
        body = strip_tags(u.content or "")
        score = _score(query_words, u.title + " " + (u.excerpt or "") + " " + body)
        if score > best_score:
            best_score, best = score, u
    if best_score >= 2 and best:
        excerpt = best.excerpt or strip_tags(best.content)[:250]
        return f"{excerpt}\n\n[Read more: {best.title}](/updates/{best.slug}/)"
    return None


# ---------------------------------------------------------------------------
# Rule-based main
# ---------------------------------------------------------------------------

def _rule_based_reply(user_message):
    msg = user_message.lower()
    site = SiteSetting.get()

    # 1. Curated KB — fastest, most precise
    for k in ChatbotKnowledge.objects.filter(is_active=True).order_by("order"):
        keywords = [kw.strip().lower() for kw in (k.keywords or "").split(",") if kw.strip()]
        if any(kw in msg for kw in keywords):
            return k.answer

    # 2. Extract meaningful words for database search
    query_words = _keywords(user_message)

    # 3. Search FAQs
    if len(query_words) >= 2:
        answer = _search_faqs(query_words)
        if answer:
            return answer

    # 4. Search property listings
    if len(query_words) >= 1:
        answer = _search_properties(query_words, msg)
        if answer:
            return answer

    # 5. Search blog / sales updates
    if len(query_words) >= 2:
        answer = _search_updates(query_words)
        if answer:
            return answer

    # 6. Intent buckets — catch common patterns the search may miss
    if any(w in msg for w in ["hello", "hi ", "hey ", "good morning", "good afternoon", "good evening"]):
        return (
            f"Hello! Welcome to {site.site_name}. I can help you find properties, "
            "lands, or answer questions about our services. What are you looking for?"
        )

    if any(w in msg for w in ["price", "cost", "how much", "budget"]):
        return (
            "Our properties span many price points. Browse at /properties/, "
            "filter by budget, or share your requirements and I'll find matches."
        )

    if any(w in msg for w in ["land", "plot"]):
        return (
            "We have verified land listings with proper titles (C of O, Governor's Consent). "
            "Visit /properties/?category=land or tell me your preferred location and budget."
        )

    if any(w in msg for w in ["rent", "apartment", "flat"]):
        return (
            "We have rental properties across Lagos, Abuja, and more. "
            "Browse at /properties/?listing_type=rent — want me to filter by area?"
        )

    if any(w in msg for w in ["buy", "sale", "purchase", "house"]):
        return (
            "We have houses and apartments for sale nationwide. "
            "See listings at /properties/?listing_type=sale. What location interests you?"
        )

    if any(w in msg for w in ["contact", "agent", "speak", "call", "human", "whatsapp"]):
        return (
            f"You can reach our team directly:\n"
            f"Phone: {site.phone}\n"
            f"Email: {site.email}\n"
            f"WhatsApp: https://wa.me/{site.whatsapp_number}"
        )

    if any(w in msg for w in ["view", "inspect", "tour", "schedule", "visit"]):
        return (
            "To schedule a viewing, share your name, phone number, and the property you'd like to see. "
            "An agent will call you within 24 hours."
        )

    if any(w in msg for w in ["document", "title", "c of o", "governor", "survey", "deed"]):
        return (
            "All our properties come with verified titles — C of O, Governor's Consent, "
            "or Deed of Assignment depending on the property. Each listing shows the title type."
        )

    if any(w in msg for w in ["mortgage", "loan", "finance", "payment plan", "installment", "instalment", "spread"]):
        return (
            "Yes, we offer flexible payment plans for many of our properties — typically 6 to 24 months "
            "depending on the unit. Would you like an agent to discuss the specific terms for a property you're interested in?"
        )

    # 7. Generic fallback
    return (
        "I'd be happy to help! Could you tell me more — type of property, location, or budget? "
        f"Or speak directly with an agent at {site.phone}."
    )


# ---------------------------------------------------------------------------
# Public entry point
# ---------------------------------------------------------------------------

def get_reply(history, user_message):
    """history = list of ChatMessage; user_message = current input string."""
    if settings.ANTHROPIC_API_KEY and settings.AI_PROVIDER == "anthropic":
        try:
            return _anthropic_reply(list(history), user_message), "anthropic"
        except Exception as e:
            print(f"[chatbot] Anthropic error: {e}")
    return _rule_based_reply(user_message), "rule_based"
