"""P4 tests — afs_share: shareable result pages.

Tests verify:
  1. store_share + get_share round-trip by share_id
  2. expires_at field present and ~30 days from now
  3. URL has correct format with share_id embedded and correct base
  4. ablation_id reference preserved in stored doc
  5. sensitivity dict preserved in stored doc
  6. Empty strategies list returns error dict (not a crash)
"""

import sys
import os
import asyncio
from datetime import datetime, timezone, timedelta
from unittest.mock import patch

sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))

from afs.store import share_store
from afs.mcp.server import afs_share


# ─── Helpers ──────────────────────────────────────────────────────────────────

def _fake_strategies():
    return [
        {
            "label": "PostgreSQL",
            "cell_count": 272,
            "values": {"performance": 83.0, "cost": 55.0},
            "concept_weights": {"PostgreSQL": 0.68},
            "is_emergent": False,
            "is_mixed": False,
            "centroid_raw": [0.83, 0.55],
            "sub_strategies": [],
        },
        {
            "label": "MongoDB",
            "cell_count": 61,
            "values": {"performance": 58.0, "cost": 43.0},
            "concept_weights": {"MongoDB": 0.67},
            "is_emergent": False,
            "is_mixed": False,
            "centroid_raw": [0.58, 0.43],
            "sub_strategies": [],
        },
    ]


# ─── Tests ────────────────────────────────────────────────────────────────────

def test_share_stores_and_retrieves():
    """store_share then get_share returns the same share_id and question."""
    share_store._reset()
    uri = os.environ.get("SHARE_MONGO_URI")
    if not uri:
        print("  SKIP: SHARE_MONGO_URI not set")
        return

    doc = {
        "question": "Which database for SaaS analytics?",
        "strategies": _fake_strategies(),
        "expires_at": datetime.now(timezone.utc) + timedelta(days=30),
        "ablation_id": None,
        "sensitivity": None,
    }
    share_id = share_store.store_share(doc)
    assert share_id and len(share_id) == 36, f"Expected UUID, got: {share_id}"

    retrieved = share_store.get_share(share_id)
    assert retrieved is not None, f"Doc not found for share_id={share_id}"
    assert retrieved["share_id"] == share_id
    assert retrieved["question"] == doc["question"]
    assert "_id" not in retrieved, "_id should be excluded"
    assert "strategies" in retrieved
    assert len(retrieved["strategies"]) == 2

    print(f"  stored and retrieved share_id={share_id}")


def test_share_expires():
    """expires_at is present and approximately 30 days from now."""
    share_store._reset()
    uri = os.environ.get("SHARE_MONGO_URI")
    if not uri:
        print("  SKIP: SHARE_MONGO_URI not set")
        return

    doc = {
        "question": "Expiry test",
        "strategies": _fake_strategies(),
        "expires_at": datetime.now(timezone.utc) + timedelta(days=30),
        "ablation_id": None,
        "sensitivity": None,
    }
    share_id = share_store.store_share(doc)
    retrieved = share_store.get_share(share_id)

    assert retrieved is not None
    assert "expires_at" in retrieved

    expires_at = retrieved["expires_at"]
    if isinstance(expires_at, datetime):
        now = datetime.now(timezone.utc)
        delta = expires_at - now
        assert 28 <= delta.days <= 31, \
            f"Expected ~30 days TTL, got {delta.days} days"
        print(f"  expires_at is {delta.days} days from now — OK")
    else:
        print(f"  expires_at type={type(expires_at)} — not a datetime, skipping range check")


def test_share_url_format():
    """URL contains share_id and correct base; share_id is a valid UUID."""
    async def _run():
        return await afs_share(
            strategies=_fake_strategies(),
            question="Which database for SaaS analytics?",
        )

    result = asyncio.run(_run())

    assert "error" not in result, f"Unexpected error: {result.get('error')}"
    assert "url" in result
    assert "share_id" in result
    assert "expires_at" in result

    share_id = result["share_id"]
    url = result["url"]

    # share_id is a UUID
    assert len(share_id) == 36, f"share_id should be UUID, got: {share_id}"
    assert share_id.count("-") == 4

    # URL contains the share_id
    assert share_id in url, f"share_id not found in URL: {url}"

    # URL ends with /share/<share_id>
    assert url.endswith(f"/share/{share_id}"), f"Unexpected URL format: {url}"

    # Default base is rezend.ai
    base = os.environ.get("SHARE_BASE_URL", "https://rezend.ai").rstrip("/")
    assert url.startswith(base), f"URL should start with {base}, got: {url}"

    print(f"  url={url}")


def test_share_with_ablation_id():
    """ablation_id reference is preserved in the stored document."""
    share_store._reset()
    uri = os.environ.get("SHARE_MONGO_URI")
    if not uri:
        print("  SKIP: SHARE_MONGO_URI not set")
        return

    fake_ablation_id = "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
    doc = {
        "question": "Ablation reference test",
        "strategies": _fake_strategies(),
        "expires_at": datetime.now(timezone.utc) + timedelta(days=30),
        "ablation_id": fake_ablation_id,
        "sensitivity": None,
    }
    share_id = share_store.store_share(doc)
    retrieved = share_store.get_share(share_id)

    assert retrieved is not None
    assert retrieved.get("ablation_id") == fake_ablation_id, \
        f"Expected ablation_id={fake_ablation_id}, got {retrieved.get('ablation_id')}"

    print(f"  ablation_id={fake_ablation_id} preserved in share doc")


def test_share_with_sensitivity():
    """sensitivity dict is preserved in the stored document."""
    share_store._reset()
    uri = os.environ.get("SHARE_MONGO_URI")
    if not uri:
        print("  SKIP: SHARE_MONGO_URI not set")
        return

    sensitivity = {
        "stability_score": 77,
        "rank_stability": 0.8,
        "sensitivity_high": False,
        "top_strategy": "PostgreSQL",
    }
    doc = {
        "question": "Sensitivity preservation test",
        "strategies": _fake_strategies(),
        "expires_at": datetime.now(timezone.utc) + timedelta(days=30),
        "ablation_id": None,
        "sensitivity": sensitivity,
    }
    share_id = share_store.store_share(doc)
    retrieved = share_store.get_share(share_id)

    assert retrieved is not None
    stored_sensitivity = retrieved.get("sensitivity")
    assert stored_sensitivity is not None, "sensitivity missing from stored doc"
    assert stored_sensitivity["stability_score"] == 77
    assert stored_sensitivity["top_strategy"] == "PostgreSQL"

    print(f"  sensitivity stability_score={stored_sensitivity['stability_score']} preserved")


def test_share_invalid_strategies_rejected():
    """Empty strategies list returns an error dict — no crash, no share stored."""
    async def _run():
        return await afs_share(
            strategies=[],
            question="This should fail",
        )

    result = asyncio.run(_run())

    assert "error" in result, f"Expected error key in result, got: {result}"
    assert "url" not in result, "URL should not be present when strategies is empty"
    assert "share_id" not in result

    print(f"  empty strategies rejected: error='{result['error']}'")


# ─── Runner ───────────────────────────────────────────────────────────────────

if __name__ == "__main__":
    tests = [
        test_share_stores_and_retrieves,
        test_share_expires,
        test_share_url_format,
        test_share_with_ablation_id,
        test_share_with_sensitivity,
        test_share_invalid_strategies_rejected,
    ]

    passed = 0
    failed = 0
    for test_fn in tests:
        name = test_fn.__name__
        try:
            test_fn()
            print(f"PASS  {name}")
            passed += 1
        except Exception as exc:
            print(f"FAIL  {name}: {exc}")
            import traceback
            traceback.print_exc()
            failed += 1

    print(f"\n{passed}/{passed + failed} tests passed")
    if failed:
        sys.exit(1)
