"""Backend tests for PerdeSahne theater portal."""
import os
import pytest
import requests

BASE_URL = os.environ.get("REACT_APP_BACKEND_URL", "https://theater-tickets-1.preview.emergentagent.com").rstrip("/")
API = f"{BASE_URL}/api"


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


# ---------- Content endpoints ----------
class TestContent:
    def test_plays_list(self, client):
        r = client.get(f"{API}/plays")
        assert r.status_code == 200
        plays = r.json()
        assert isinstance(plays, list)
        assert len(plays) == 6, f"Expected 6 plays, got {len(plays)}"
        # validate structure
        p = plays[0]
        for k in ["id", "title", "genre", "venue", "age_limit", "prices", "showtimes"]:
            assert k in p
        # Save id for next tests
        pytest.play_id = p["id"]
        pytest.first_showtime_id = p["showtimes"][0]["id"]
        pytest.play_prices = p["prices"]

    def test_plays_filter_genre(self, client):
        r = client.get(f"{API}/plays", params={"genre": "Komedi"})
        assert r.status_code == 200
        plays = r.json()
        assert len(plays) >= 1
        assert all(p["genre"] == "Komedi" for p in plays)

    def test_plays_filter_venue(self, client):
        r = client.get(f"{API}/plays", params={"venue": "Ana Sahne"})
        assert r.status_code == 200
        assert all(p["venue"] == "Ana Sahne" for p in r.json())

    def test_plays_filter_age(self, client):
        r = client.get(f"{API}/plays", params={"age_limit": "13+"})
        assert r.status_code == 200
        assert all(p["age_limit"] == "13+" for p in r.json())

    def test_plays_search(self, client):
        r = client.get(f"{API}/plays", params={"search": "hamlet"})
        assert r.status_code == 200
        titles = [p["title"].lower() for p in r.json()]
        assert any("hamlet" in t for t in titles)

    def test_play_detail(self, client):
        r = client.get(f"{API}/plays/{pytest.play_id}")
        assert r.status_code == 200
        assert r.json()["id"] == pytest.play_id

    def test_play_detail_404(self, client):
        r = client.get(f"{API}/plays/nonexistent-id")
        assert r.status_code == 404

    def test_showtimes(self, client):
        r = client.get(f"{API}/showtimes")
        assert r.status_code == 200
        events = r.json()
        assert isinstance(events, list)
        assert len(events) > 0
        # Sorted by date+time
        dates = [(e["date"], e["time"]) for e in events]
        assert dates == sorted(dates)

    def test_team(self, client):
        r = client.get(f"{API}/team")
        assert r.status_code == 200
        team = r.json()
        assert len(team) > 0
        assert any(m["type"] == "cast" for m in team)
        assert any(m["type"] == "crew" for m in team)

    def test_news(self, client):
        r = client.get(f"{API}/news")
        assert r.status_code == 200
        news = r.json()
        assert len(news) > 0
        pytest.news_id = news[0]["id"]

    def test_news_detail(self, client):
        r = client.get(f"{API}/news/{pytest.news_id}")
        assert r.status_code == 200
        assert r.json()["id"] == pytest.news_id

    def test_news_detail_404(self, client):
        r = client.get(f"{API}/news/invalid-id")
        assert r.status_code == 404

    def test_gallery(self, client):
        r = client.get(f"{API}/gallery")
        assert r.status_code == 200
        assert len(r.json()) > 0

    def test_stats(self, client):
        r = client.get(f"{API}/stats")
        assert r.status_code == 200
        d = r.json()
        for k in ["total_plays", "total_audience", "active_artists", "upcoming_events"]:
            assert k in d
        assert d["total_plays"] == 6


# ---------- Contact + Newsletter ----------
class TestForms:
    def test_contact(self, client):
        r = client.post(f"{API}/contact", json={
            "name": "TEST_User",
            "email": "test_contact@example.com",
            "message": "Test message"
        })
        assert r.status_code == 200
        assert r.json()["success"] is True

    def test_newsletter_new(self, client):
        email = f"TEST_news_{os.urandom(4).hex()}@example.com"
        r = client.post(f"{API}/newsletter", json={"email": email})
        assert r.status_code == 200
        data = r.json()
        assert data["success"] is True
        assert "başarıyla" in data["message"]
        # Subscribe again -> already subscribed
        r2 = client.post(f"{API}/newsletter", json={"email": email})
        assert r2.status_code == 200
        assert "zaten kayıtlı" in r2.json()["message"]


# ---------- Discount ----------
class TestDiscount:
    def test_valid_code(self, client):
        r = client.post(f"{API}/discount/validate", json={"code": "TIYATRO10"})
        assert r.status_code == 200
        d = r.json()
        assert d["valid"] is True
        assert d["percent"] == 10

    def test_valid_code_perde20(self, client):
        r = client.post(f"{API}/discount/validate", json={"code": "PERDE20"})
        assert r.json()["percent"] == 20

    def test_invalid_code(self, client):
        r = client.post(f"{API}/discount/validate", json={"code": "FAKE"})
        assert r.json()["valid"] is False

    def test_case_insensitive(self, client):
        r = client.post(f"{API}/discount/validate", json={"code": "tiyatro10"})
        assert r.json()["valid"] is True


# ---------- Checkout ----------
class TestCheckout:
    def _create_payload(self, play_id, showtime_id, **overrides):
        payload = {
            "play_id": play_id,
            "showtime_id": showtime_id,
            "category": "normal",
            "quantity": 2,
            "discount_code": "TIYATRO10",
            "customer_name": "TEST_Customer",
            "customer_email": "test@example.com",
            "origin_url": BASE_URL,
        }
        payload.update(overrides)
        return payload

    def test_create_checkout_valid_with_discount(self, client):
        # Use the first play with normal price 450 (Bir Yaz Gecesi Rüyası)
        r = client.get(f"{API}/plays")
        plays = r.json()
        target = next((p for p in plays if p["prices"]["normal"] == 450.0), None)
        assert target is not None, "Couldn't find play with normal=450"
        pytest.target_play = target
        showtime_id = target["showtimes"][0]["id"]

        payload = self._create_payload(target["id"], showtime_id)
        res = client.post(f"{API}/checkout/session", json=payload)
        assert res.status_code == 200, f"Got {res.status_code}: {res.text}"
        data = res.json()
        assert "url" in data
        assert "session_id" in data
        assert "stripe.com" in data["url"] or "checkout" in data["url"].lower()
        pytest.test_session_id = data["session_id"]

    def test_checkout_status_unpaid(self, client):
        r = client.get(f"{API}/checkout/status/{pytest.test_session_id}")
        assert r.status_code == 200
        d = r.json()
        # Stripe checkout session typically open/unpaid right after creation
        assert d["payment_status"] in ("unpaid", "no_payment_required", None)
        assert d["ticket"] is None

    def test_invalid_category(self, client):
        target = pytest.target_play
        payload = self._create_payload(target["id"], target["showtimes"][0]["id"], category="premium")
        r = client.post(f"{API}/checkout/session", json=payload)
        assert r.status_code == 400

    def test_invalid_play(self, client):
        target = pytest.target_play
        payload = self._create_payload("nonexistent-play", target["showtimes"][0]["id"])
        r = client.post(f"{API}/checkout/session", json=payload)
        assert r.status_code == 404

    def test_invalid_showtime(self, client):
        target = pytest.target_play
        payload = self._create_payload(target["id"], "bad-showtime")
        r = client.post(f"{API}/checkout/session", json=payload)
        assert r.status_code == 404

    def test_amount_calculation_in_db(self, client):
        """Verify backend calculates 450 * 2 * 0.9 = 810.00 TRY."""
        # Look up transaction via status endpoint and confirm by re-creating
        # Since we can't directly read DB, we rely on a NEW session and trust the stored amount;
        # but we can verify via Stripe by checking session URL exists. Instead recreate and trust.
        # The status endpoint returns amount_total from Stripe in cents/units.
        target = pytest.target_play
        payload = self._create_payload(target["id"], target["showtimes"][0]["id"])
        r = client.post(f"{API}/checkout/session", json=payload)
        assert r.status_code == 200
        sid = r.json()["session_id"]
        st = client.get(f"{API}/checkout/status/{sid}")
        assert st.status_code == 200
        data = st.json()
        # Stripe returns amount_total in smallest currency unit (kuruş for TRY) -> 81000
        # but emergentintegrations may normalize. Accept either form.
        amt = data.get("amount_total")
        assert amt in (810.0, 81000, 81000.0), f"Unexpected amount_total: {amt}"

    def test_status_invalid_session(self, client):
        r = client.get(f"{API}/checkout/status/invalid-session-id")
        # Could be 404 (txn not found) or 500 from Stripe; we expect our handler => 404
        assert r.status_code in (404, 400, 500)
