"""Actionable admin dashboard tests (Phase 5.1).

Verifies clickable cards link to real routes, non-existent destinations render
disabled, table rows/sellers/ads expose the right actions, empty states show,
non-admins are denied, and no extra analytics queries were introduced.
"""

import os
import unittest
from decimal import Decimal

os.environ["TEST_DATABASE_URL"] = "sqlite:///:memory:"

from sqlalchemy import event
from werkzeug.security import generate_password_hash

from app import create_app
from app.admin.analytics import get_admin_dashboard
from app.extensions import db
from app.models import (
    Advertisement,
    AdvertisementPlacement,
    AdvertisementType,
    Category,
    Listing,
    ListingCondition,
    ListingStatus,
    ListingView,
    ListingVisibility,
    ReviewStatus,
    User,
)
from app.models.base import utcnow
from app.models.enums import UserRole


class _QueryCounter:
    def __init__(self):
        self.n = 0

    def __enter__(self):
        self._e = db.engine
        event.listen(self._e, "after_cursor_execute", self._cb)
        return self

    def __exit__(self, *a):
        event.remove(self._e, "after_cursor_execute", self._cb)

    def _cb(self, *a):
        self.n += 1


class AdminDashboardActionTests(unittest.TestCase):
    def setUp(self):
        self.app = create_app("testing")
        self.ctx = self.app.app_context()
        self.ctx.push()
        db.create_all()

    def tearDown(self):
        db.session.remove()
        db.drop_all()
        self.ctx.pop()

    def _user(self, email, role=UserRole.STUDENT):
        u = User(is_verified=True, email=email, password_hash=generate_password_hash("Passw0rd!"), role=role)
        db.session.add(u)
        db.session.commit()
        return u

    def _listing(self, seller, idx=1, views=10, category="Electronics"):
        cat = db.session.scalar(db.select(Category).filter_by(name=category))
        if cat is None:
            cat = Category(name=category, description="d", is_active=True, display_order=1)
            db.session.add(cat)
            db.session.commit()
        listing = Listing(
            sku=f"SKU-{seller.id}-{idx}", seller_id=seller.id, category_id=cat.id,
            title=f"Item {idx}", slug=f"item-{seller.id}-{idx}", description="d",
            price=Decimal("50.00"), condition=ListingCondition.GOOD, status=ListingStatus.AVAILABLE,
            visibility=ListingVisibility.PUBLIC, review_status=ReviewStatus.APPROVED, view_count=views,
        )
        db.session.add(listing)
        db.session.commit()
        return listing

    def _admin_client(self):
        self._admin = self._user("admin@c.edu", UserRole.SUPER_ADMIN)
        client = self.app.test_client()
        client.post("/login", data={"email": "admin@c.edu", "password": "Passw0rd!"})
        return client

    def _html(self, client):
        return client.get("/admin/analytics").get_data(as_text=True)

    # --- access ---
    def test_non_admin_denied(self):
        self._user("s@c.edu", UserRole.STUDENT)
        client = self.app.test_client()
        client.post("/login", data={"email": "s@c.edu", "password": "Passw0rd!"})
        self.assertEqual(client.get("/admin/analytics").status_code, 403)

    # --- clickable + disabled cards ---
    def test_existing_destination_card_is_clickable(self):
        client = self._admin_client()
        db.session.add(Advertisement(title="A", advertisement_type=AdvertisementType.BANNER,
                                     placement=AdvertisementPlacement.SIDEBAR, is_active=True, priority=1))
        db.session.commit()
        html = self._html(client)
        # Advertisements card links to the real ad list.
        self.assertIn('href="/admin/advertisements"', html)
        self.assertIn("admin-metric-clickable", html)

    def test_missing_destination_card_is_disabled(self):
        client = self._admin_client()
        html = self._html(client)
        self.assertIn("admin-metric-disabled", html)
        self.assertIn("Management page coming soon", html)
        # Still-missing admin pages (conversations/offers) are NOT linked.
        # (admin.users — Phase 6.0 — and admin.listings — Phase 6.1 — now exist,
        # so those cards are intentionally live.)
        self.assertNotIn('href="/admin/conversations"', html)
        self.assertNotIn('href="/admin/offers"', html)

    def test_top_category_card_drilldown(self):
        client = self._admin_client()
        listing = self._listing(self._user("sell@c.edu"), category="Electronics")
        db.session.add(ListingView(listing_id=listing.id, session_id="s", ip_hash="h", viewed_at=utcnow()))
        db.session.commit()
        cat = db.session.scalar(db.select(Category).filter_by(name="Electronics"))
        html = self._html(client)
        self.assertIn(f"/marketplace?category={cat.id}", html)

    # --- table actions ---
    def test_top_listing_links(self):
        client = self._admin_client()
        listing = self._listing(self._user("sell@c.edu"), views=99)
        html = self._html(client)
        self.assertIn(f"/app/listings/{listing.public_id}", html)
        self.assertIn("View Listing", html)

    def test_seller_action_links(self):
        client = self._admin_client()
        seller = self._user("sell@c.edu")
        self._listing(seller, views=99)
        html = self._html(client)
        self.assertIn(f"/users/{seller.public_id}", html)   # public profile
        self.assertIn("View Profile", html)

    def test_advertisement_action_links(self):
        client = self._admin_client()
        db.session.add(Advertisement(title="A", advertisement_type=AdvertisementType.BANNER,
                                     placement=AdvertisementPlacement.SIDEBAR, is_active=True, priority=1))
        db.session.commit()
        html = self._html(client)
        self.assertIn("Create Advertisement", html)
        self.assertIn("Manage Advertisements", html)
        self.assertIn("/admin/advertisements/new", html)         # create
        self.assertIn("/admin/advertisements?status=active", html)  # active filter

    def test_premium_action_link(self):
        client = self._admin_client()
        html = self._html(client)
        self.assertIn("Review Premium Requests", html)
        self.assertIn("/app/premium/admin/requests", html)

    # --- empty states ---
    def test_advertisement_empty_state(self):
        client = self._admin_client()  # no ads created
        html = self._html(client)
        self.assertIn("No advertisements yet", html)
        self.assertIn("Create Advertisement", html)

    # --- performance: no extra analytics queries / no N+1 from links ---
    def test_dashboard_query_count_constant(self):
        a = self._user("a@c.edu")
        b = self._user("b@c.edu")
        for i in range(3):
            self._listing(a, idx=i, views=i)
            self._listing(b, idx=i, views=i + 1)
        with _QueryCounter() as c1:
            get_admin_dashboard()
        small = c1.n
        for i in range(3, 12):
            self._listing(a, idx=i, views=i)
            self._listing(b, idx=i, views=i + 1)
        with _QueryCounter() as c2:
            get_admin_dashboard()
        self.assertEqual(small, c2.n)  # links added no per-row queries

    def test_link_identifiers_present_without_extra_queries(self):
        seller = self._user("sell@c.edu")
        self._listing(seller, category="Electronics", views=5)
        db.session.add(ListingView(
            listing_id=db.session.scalar(db.select(Listing.id)), session_id="s", ip_hash="h", viewed_at=utcnow()))
        db.session.commit()
        dash = get_admin_dashboard()
        # Identifiers exposed purely for linking.
        self.assertIsNotNone(dash["top_sellers"][0]["public_id"])
        self.assertIsNotNone(dash["traffic"]["top_category_id"])


if __name__ == "__main__":
    unittest.main()
