"""Tests for new AI Assistant capabilities: health score + smart search."""
import os
import requests

BASE_URL = os.environ.get("REACT_APP_BACKEND_URL", "https://offline-billing-pro-2.preview.emergentagent.com").rstrip("/")


class TestAIHealthAndSearch:
    def test_health_score_returns_full_payload(self, admin_session, default_company_id):
        r = admin_session.get(f"{BASE_URL}/api/ai/health-score?company_id={default_company_id}", timeout=30)
        assert r.status_code == 200, r.text
        d = r.json()
        for k in ("score", "grade", "signals", "recommendations", "generated_at"):
            assert k in d, f"missing key {k}"
        assert isinstance(d["score"], int)
        assert 0 <= d["score"] <= 100
        assert d["grade"] in ("A", "B", "C", "D", "F")
        # Must have at least 8 signals (DB, API, backup, conflicts, login, license, stock, etc.)
        assert len(d["signals"]) >= 8, f"Only {len(d['signals'])} signals"

    def test_health_signal_shape(self, admin_session, default_company_id):
        r = admin_session.get(f"{BASE_URL}/api/ai/health-score?company_id={default_company_id}", timeout=30)
        sig = r.json()["signals"][0]
        for k in ("name", "status", "weight", "detail"):
            assert k in sig
        assert sig["status"] in ("ok", "warn", "fail")

    def test_health_requires_auth(self):
        r = requests.get(f"{BASE_URL}/api/ai/health-score", timeout=15)
        assert r.status_code == 401

    def test_search_empty_query(self, admin_session, default_company_id):
        r = admin_session.get(f"{BASE_URL}/api/ai/search?q=&company_id={default_company_id}", timeout=15)
        assert r.status_code == 200
        d = r.json()
        assert d["hits"] == 0
        assert d["invoices"] == [] and d["parties"] == [] and d["items"] == []

    def test_search_short_query_ignored(self, admin_session, default_company_id):
        r = admin_session.get(f"{BASE_URL}/api/ai/search?q=a&company_id={default_company_id}", timeout=15)
        # Min length is 2 — single chars are no-ops to avoid heavy regex on big datasets
        assert r.json()["hits"] == 0

    def test_search_finds_items_or_invoices(self, admin_session, default_company_id):
        # "INV" is part of every invoice_no — guaranteed hit
        r = admin_session.get(f"{BASE_URL}/api/ai/search?q=INV&company_id={default_company_id}&limit=5", timeout=20)
        assert r.status_code == 200
        d = r.json()
        # At least one of the three groups should have results
        assert d["hits"] >= 1
        # Result shape
        if d["invoices"]:
            inv = d["invoices"][0]
            for k in ("id", "invoice_no"):
                assert k in inv

    def test_search_safe_regex(self, admin_session, default_company_id):
        # Regex meta-chars must not crash the server
        r = admin_session.get(
            f"{BASE_URL}/api/ai/search?q=.*+%5B&company_id={default_company_id}",
            timeout=15,
        )
        assert r.status_code == 200, r.text

    def test_search_requires_auth(self):
        r = requests.get(f"{BASE_URL}/api/ai/search?q=test", timeout=15)
        assert r.status_code == 401

    def test_chat_uses_app_guide_for_how_to(self, admin_session, default_company_id):
        """When user asks 'how to ...', AI should reference the workflow guide
        (look for menu / sidebar terminology, not invented UI)."""
        r = admin_session.post(
            f"{BASE_URL}/api/ai/chat",
            json={
                "message": "How do I create a sale invoice?",
                "company_id": default_company_id,
                "session_id": "test-howto",
            },
            timeout=45,
        )
        assert r.status_code == 200, r.text
        reply = r.json()["reply"].lower()
        # Reply should reference invoice creation in some grounded way
        assert any(token in reply for token in ("invoice", "new", "save", "sale", "बिल"))
