"""Advertisement Management UI/UX & accessibility polish tests.

Server-renderable aspects of the polish pass: context-aware empty states, chart
accessibility (role/aria-label + screen-reader summaries), video hover-preview
hooks, focus/skeleton markup, and responsive containers. (Interactive JS
behaviour — hover timing, focus trapping — is verified via the markup hooks it
relies on, since it cannot execute under the server-side test client.)
"""

import os
import unittest

os.environ["TEST_DATABASE_URL"] = "sqlite:///:memory:"

from werkzeug.security import generate_password_hash

from app import create_app
from app.extensions import db
from app.models import (
    Advertisement,
    AdvertisementMediaType,
    AdvertisementPlacement,
    AdvertisementType,
    RewardedAdEvent,
    User,
    UserRole,
)


class AdUiPolishTests(unittest.TestCase):
    def setUp(self):
        self.app = create_app("testing")
        self.ctx = self.app.app_context()
        self.ctx.push()
        db.create_all()
        u = User(email="a@c.edu", password_hash=generate_password_hash("Passw0rd!"),
                 is_verified=True, role=UserRole.SUPER_ADMIN)
        db.session.add(u)
        db.session.commit()
        self.client = self.app.test_client()
        self.client.post("/login", data={"email": "a@c.edu", "password": "Passw0rd!"})

    def tearDown(self):
        db.session.remove()
        db.drop_all()
        self.ctx.pop()

    def _video_ad(self, title="Vid"):
        ad = Advertisement(title=title, advertisement_type=AdvertisementType.REWARDED,
                           placement=AdvertisementPlacement.CHAT,
                           media_type=AdvertisementMediaType.VIDEO,
                           media_url="/static/uploads/advertisements/x.mp4",
                           video_duration=15, is_active=True, priority=5)
        db.session.add(ad)
        db.session.commit()
        return ad

    def _image_ad(self, title="Img"):
        ad = Advertisement(title=title, advertisement_type=AdvertisementType.BANNER,
                           placement=AdvertisementPlacement.MARKETPLACE,
                           image_path="/static/uploads/advertisements/i.png",
                           is_active=True, priority=5)
        db.session.add(ad)
        db.session.commit()
        return ad

    def _list(self, qs=""):
        return self.client.get("/admin/advertisements" + qs).get_data(as_text=True)

    # --- Phase 4: context-aware empty states ----------------------------------
    def test_empty_state_no_ads(self):
        html = self._list()
        self.assertIn("No advertisements have been created", html)
        self.assertIn("Create advertisement", html)

    def test_empty_state_search(self):
        self._image_ad()
        html = self._list("?q=nomatchxyz")
        self.assertIn("No advertisements match your search", html)
        self.assertIn("nomatchxyz", html)

    def test_empty_state_video_filter(self):
        self._image_ad()
        html = self._list("?media_type=video")
        self.assertIn("No video advertisements found", html)

    def test_empty_state_image_filter(self):
        self._video_ad()
        html = self._list("?media_type=image")
        self.assertIn("No image advertisements found", html)

    def test_empty_state_rewarded_filter(self):
        self._image_ad()
        html = self._list("?placement=chat")
        self.assertIn("No rewarded advertisements", html)

    def test_empty_state_generic_filter(self):
        self._image_ad()
        html = self._list("?status=expired")
        self.assertIn("No advertisements match your filters", html)

    def test_empty_state_has_status_role(self):
        html = self._list()
        self.assertIn('role="status"', html)   # announced to screen readers

    # --- Phase 3: accessibility -----------------------------------------------
    def test_charts_have_accessible_role_and_label(self):
        self._image_ad()
        for _ in range(2):  # ensure charts render (has_data)
            self._image_ad()
        html = self._list()
        self.assertIn('role="img"', html)
        self.assertIn("Bar chart comparing impressions and clicks", html)
        self.assertIn("Doughnut chart of campaign counts by placement", html)
        # A screen-reader text summary accompanies the chart (not colour-only).
        self.assertIn("impressions and", html)

    def test_analytics_charts_have_aria(self):
        self._image_ad()
        html = self.client.get("/admin/advertisements/analytics").get_data(as_text=True)
        self.assertIn('id="chartImpressions" role="img"', html)
        self.assertIn("aria-label", html)

    def test_per_ad_chart_has_aria(self):
        ad = self._video_ad()
        db.session.add(RewardedAdEvent(advertisement_id=ad.id, event_type="impression"))
        db.session.add(RewardedAdEvent(advertisement_id=ad.id, event_type="reward_granted"))
        db.session.commit()
        html = self.client.get(f"/admin/advertisements/{ad.public_id}/stats").get_data(as_text=True)
        self.assertIn('id="chartAdFunnel" role="img"', html)
        self.assertIn("Reward funnel:", html)

    def test_decorative_icons_hidden_in_empty_state(self):
        html = self._list()
        self.assertIn('class="empty-state-icon" aria-hidden="true"', html)

    # --- Phase 2: video hover preview hooks -----------------------------------
    def test_video_thumbnail_exposes_preview_source(self):
        self._video_ad()
        html = self._list()
        # Hover-preview reads these off the thumbnail button; it uses the uploaded
        # file directly (no rewarded route) — assert the source + type are present.
        self.assertIn('data-media-type="video"', html)
        self.assertIn('data-media-src="/static/uploads/advertisements/x.mp4"', html)

    def test_hover_preview_not_using_reward_endpoints(self):
        self._video_ad()
        before = db.session.scalar(db.select(db.func.count(RewardedAdEvent.id)))
        self._list()
        after = db.session.scalar(db.select(db.func.count(RewardedAdEvent.id)))
        self.assertEqual(before, after)   # rendering/preview records no analytics

    # --- Phase 1/6: skeleton + entrance hooks ---------------------------------
    def test_chart_skeleton_hook_present(self):
        for _ in range(3):
            self._image_ad()
        html = self._list()
        self.assertIn("ad-chart-box", html)   # shimmer skeleton wrapper on charts


if __name__ == "__main__":
    unittest.main()
