"""Backend tests for ASEAN Bakery & Cake API.

Covers:
- Health endpoint
- POST /api/estimate-price (Gemini 3 via Emergent LLM)
- MongoDB persistence in collection `price_estimates`
"""

import os
import re
import pytest
import requests
from pymongo import MongoClient

BASE_URL = os.environ.get("REACT_APP_BACKEND_URL", "https://bakery-ai-pricing.preview.emergentagent.com").rstrip("/")
MONGO_URL = os.environ.get("MONGO_URL", "mongodb://localhost:27017")
DB_NAME = os.environ.get("DB_NAME", "test_database")


@pytest.fixture(scope="module")
def api():
    s = requests.Session()
    s.headers.update({"Content-Type": "application/json"})
    return s


@pytest.fixture(scope="module")
def mongo():
    client = MongoClient(MONGO_URL, serverSelectionTimeoutMS=3000)
    yield client[DB_NAME]
    client.close()


# ---------- Health ----------
class TestHealth:
    def test_root_running(self, api):
        r = api.get(f"{BASE_URL}/api/", timeout=15)
        assert r.status_code == 200
        body = r.json()
        assert "message" in body
        assert "running" in body["message"].lower()


# ---------- Price Estimator ----------
ITEMS = [
    {"cake_type": "Birthday Cake", "size": "Medium (10-14 servings)", "flavor": "chocolate", "extras": "sprinkles"},
    {"cake_type": "Fudge Brownies", "size": "Small (6-8 servings)", "flavor": "dark chocolate", "extras": "walnuts"},
    {"cake_type": "Macaroni Schotel", "size": "Large (16-20 servings)", "flavor": "three cheese", "extras": "none"},
    {"cake_type": "Cupcakes (dozen)", "size": "Party (24+ servings)", "flavor": "vanilla", "extras": "buttercream rosettes"},
]


@pytest.mark.parametrize("payload", ITEMS, ids=[i["cake_type"] for i in ITEMS])
def test_estimate_price_valid_items(api, payload):
    r = api.post(f"{BASE_URL}/api/estimate-price", json=payload, timeout=60)
    assert r.status_code == 200, f"Unexpected status {r.status_code}: {r.text}"
    data = r.json()
    # required fields
    for key in ("id", "cake_type", "size", "price_low", "price_high", "currency", "reasoning", "timestamp"):
        assert key in data, f"Missing key {key} in response"
    assert data["currency"] == "USD"
    assert isinstance(data["price_low"], (int, float))
    assert isinstance(data["price_high"], (int, float))
    assert data["price_low"] > 0 and data["price_high"] > 0
    assert data["price_low"] <= data["price_high"], "price_low must be <= price_high"
    assert data["cake_type"] == payload["cake_type"]
    assert data["size"] == payload["size"]
    assert isinstance(data["reasoning"], str) and len(data["reasoning"].strip()) > 0


FALLBACK_REASONING = "Estimated using typical Colorado homemade bakery rates (fallback)."


def test_estimate_price_calls_real_gemini(api):
    """Verify reasoning is NOT the fallback string -> Gemini was actually invoked."""
    r = api.post(f"{BASE_URL}/api/estimate-price", json={
        "cake_type": "Birthday Cake",
        "size": "Medium (10-14 servings)",
        "flavor": "red velvet",
        "extras": "cream cheese frosting",
    }, timeout=60)
    assert r.status_code == 200
    data = r.json()
    # Distinct from fallback exact string and fallback default prices 25/45
    is_fallback_text = data["reasoning"].strip() == FALLBACK_REASONING
    is_fallback_prices = data["price_low"] == 25.0 and data["price_high"] == 45.0
    assert not is_fallback_text, "Got fallback reasoning – Gemini likely not called"
    assert not is_fallback_prices, "Got fallback prices – Gemini likely not called"


def test_estimate_price_persists_to_mongo(api, mongo):
    flavor_tag = "TEST_persist_check_xyz"
    r = api.post(f"{BASE_URL}/api/estimate-price", json={
        "cake_type": "Cake Tape",
        "size": "Small (6-8 servings)",
        "flavor": flavor_tag,
        "extras": "",
    }, timeout=60)
    assert r.status_code == 200
    doc_id = r.json()["id"]
    doc = mongo.price_estimates.find_one({"id": doc_id})
    assert doc is not None, "Price estimate not persisted to MongoDB"
    assert doc["flavor"] == flavor_tag
    assert doc["currency"] == "USD"
    assert doc["price_low"] <= doc["price_high"]
    # cleanup
    mongo.price_estimates.delete_one({"id": doc_id})


def test_estimate_price_invalid_payload(api):
    """Missing required fields should yield 422."""
    r = api.post(f"{BASE_URL}/api/estimate-price", json={"flavor": "vanilla"}, timeout=15)
    assert r.status_code == 422
