import contextlib
import json
import threading

import xbmcgui

from lib.api.fanart.fanart import get_fanart
from lib.api.imdb.imdb_scraper import get_imdb_extras
from lib.clients.tmdb.utils.utils import LANGUAGES, tmdb_get
from lib.gui.base_window import BaseWindow
from lib.utils.general.utils import truncate_text
from lib.utils.kodi.utils import (
    ADDON_PATH,
    build_url,
    execute_builtin,
    get_setting,
    kodilog,
    notification,
    translation,
)


class ExtrasWindow(BaseWindow):
    def __init__(self, xml_file, location, item_information=None, previous_window=None):
        super().__init__(xml_file, location, item_information, previous_window)
        self.tmdb_id = self.item_information.get("tmdb_id")
        self.media_type = self.item_information.get("media_type")  # "movie" or "tv"
        self.imdb_id = self.item_information.get("imdb_id", "")
        self.title = self.item_information.get("title", "")

        # Shared TMDB details data (populated by fetch_details_and_artwork)
        self._tmdb_data = None
        self._details_ready = threading.Event()

        # UI Lists
        self.cast_list_id = 2050
        self.recommended_list_id = 2051
        self.similar_list_id = 2052
        self.ai_similar_list_id = 2053
        self.reviews_list_id = 2054
        self.comments_list_id = 2055
        self.trivia_list_id = 2056
        self.blunders_list_id = 2057
        self.parental_guide_list_id = 2058
        self.trakt_lists_id = 2059
        self.youtube_list_id = 2060
        self.more_year_list_id = 2061
        self.more_genres_list_id = 2062
        self.more_networks_list_id = 2063
        self.collection_list_id = 2064

    def onInit(self):
        super().onInit()
        self._init_properties()
        self.set_button_labels()

        # Start background threads to fetch data so GUI doesn't freeze
        threading.Thread(target=self.fetch_details_and_artwork, daemon=True).start()
        threading.Thread(target=self.fetch_cast, daemon=True).start()
        threading.Thread(target=self.fetch_recommended, daemon=True).start()
        threading.Thread(target=self.fetch_similar, daemon=True).start()
        threading.Thread(target=self.fetch_imdb_data, daemon=True).start()

        # Threads that depend on TMDB details being fetched first
        threading.Thread(target=self._fetch_after_details, daemon=True).start()

        # Set focus to Play button initially
        self.setFocusId(10)

    def _init_properties(self):
        """Initialize all window properties to safe defaults."""
        self.setProperty("title", self.title)
        self.setProperty("clearlogo", "false")
        self.setProperty("fanart", "false")
        self.setProperty("poster", "false")
        self.setProperty("plot_enabled", "false")
        self.setProperty("plot", "")
        self.setProperty("genre", "")
        self.setProperty("tmdb_rating", "false")
        self.setProperty("imdb_rating", "false")
        self.setProperty("metascore_rating", "false")
        self.setProperty("tomatometer_rating", "false")
        self.setProperty("tomatousermeter_rating", "false")
        self.setProperty("display_extra_ratings", "false")
        # Tab system
        self.setProperty("active_tab", "overview")

    def _fetch_after_details(self):
        """Wait for TMDB details fetch, then populate sections that depend on it."""
        self._details_ready.wait(timeout=15)
        if not self._tmdb_data:
            return
        try:
            self._populate_youtube_videos()
        except Exception as e:
            kodilog(f"Error populating YouTube videos: {e}")
        try:
            self._populate_collection()
        except Exception as e:
            kodilog(f"Error populating collection: {e}")
        try:
            self._populate_more_from_year()
        except Exception as e:
            kodilog(f"Error populating more from year: {e}")
        try:
            self._populate_more_from_genres()
        except Exception as e:
            kodilog(f"Error populating more from genres: {e}")
        try:
            self._populate_more_from_networks()
        except Exception as e:
            kodilog(f"Error populating more from networks: {e}")
        try:
            self.fetch_ai_similar()
        except Exception as e:
            kodilog(f"Error populating AI similar: {e}")

    # ─── TMDB Details + Artwork ───────────────────────────────────────────────

    def fetch_details_and_artwork(self):
        try:
            path = "movie_details" if self.media_type == "movie" else "tv_details"
            data = tmdb_get(path, {"id": self.tmdb_id})
            self._tmdb_data = data

            poster = ""
            fanart = ""
            tvdb_id = None

            if data:
                # ── Extract metadata ──
                self._populate_metadata(data)

                # ── Extract images ──
                poster_path = getattr(data, "poster_path", "")
                if poster_path:
                    poster = f"https://image.tmdb.org/t/p/w500{poster_path}"

                backdrop_path = getattr(data, "backdrop_path", "")
                if backdrop_path:
                    fanart = f"https://image.tmdb.org/t/p/original{backdrop_path}"

                if self.media_type != "movie":
                    external_ids = getattr(data, "external_ids", None)
                    if external_ids:
                        tvdb_id = external_ids.get("tvdb_id")
                        if not self.imdb_id:
                            self.imdb_id = external_ids.get("imdb_id", "")
                else:
                    if not self.imdb_id:
                        self.imdb_id = getattr(data, "imdb_id", "") or ""

            # ── Fanart.tv for clearlogo and better backgrounds ──
            language_index = get_setting("language", 18)
            lang = "en"
            with contextlib.suppress(Exception):
                lang = LANGUAGES[int(language_index)].split("-")[0]

            media_type_fa = "movies" if self.media_type == "movie" else "tv"
            fa_id = str(self.tmdb_id)
            if self.media_type != "movie" and tvdb_id:
                fa_id = str(tvdb_id)

            fa_data = get_fanart(media_type_fa, lang, fa_id)

            clearlogo = fa_data.get("clearlogo", "")
            if fa_data.get("fanart"):
                fanart = fa_data.get("fanart")
            if fa_data.get("poster"):
                poster = fa_data.get("poster")

            # Set properties if found
            if poster:
                self.setProperty("poster", poster)
            if fanart:
                self.setProperty("fanart", fanart)
            if clearlogo:
                self.setProperty("clearlogo", clearlogo)
            else:
                self.setProperty("clearlogo", "false")

        except Exception as e:
            kodilog(f"Error fetching details/artwork for extras: {e}")
        finally:
            self._details_ready.set()

    def _populate_metadata(self, data):
        """Extract and set genre, plot, rating, year, and runtime from TMDB details."""
        try:
            # Genre
            genres = getattr(data, "genres", None)
            if genres:
                genre_names = []
                for g in genres:
                    name = g.get("name", "") if hasattr(g, "get") else getattr(g, "name", "")
                    if name:
                        genre_names.append(name)
                if genre_names:
                    self.setProperty("genre", " / ".join(genre_names))

            # Plot
            overview = getattr(data, "overview", "")
            if overview:
                self.setProperty("plot_enabled", "true")
                self.setProperty("plot", truncate_text(str(overview)))

            # Rating (TMDB)
            vote_average = getattr(data, "vote_average", None)
            if vote_average and float(vote_average) > 0:
                self.setProperty("tmdb_rating", "true")
                with contextlib.suppress(Exception):
                    self.getControl(4005).setLabel(f"{float(vote_average):.1f}")

            # Year and runtime — populate Line 2 (control 2001)
            line2_parts = []
            if self.media_type == "movie":
                release_date = getattr(data, "release_date", "")
                if release_date:
                    line2_parts.append(str(release_date)[:4])
                runtime = getattr(data, "runtime", None)
                if runtime:
                    hours = int(runtime) // 60
                    mins = int(runtime) % 60
                    if hours:
                        line2_parts.append(f"{hours}h {mins}m")
                    else:
                        line2_parts.append(f"{mins}m")
            else:
                first_air = getattr(data, "first_air_date", "")
                if first_air:
                    line2_parts.append(str(first_air)[:4])
                num_seasons = getattr(data, "number_of_seasons", None)
                if num_seasons:
                    line2_parts.append(
                        f"{num_seasons} Season{'s' if int(num_seasons) != 1 else ''}"
                    )
                status = getattr(data, "status", "")
                if status:
                    line2_parts.append(str(status))

            if line2_parts:
                with contextlib.suppress(Exception):
                    self.getControl(2001).setLabel("  •  ".join(line2_parts))

            # Vote count / Tagline — populate Line 3 (control 3001)
            tagline = getattr(data, "tagline", "")
            if tagline:
                with contextlib.suppress(Exception):
                    self.getControl(3001).setLabel(f"[I]{tagline}[/I]")

        except Exception as e:
            kodilog(f"Error populating metadata: {e}")

    # ─── Button Labels ────────────────────────────────────────────────────────

    def set_button_labels(self):
        self.setProperty("button10.label", translation(90413))
        self.setProperty("button11.label", translation(90414))
        self.setProperty("button15.label", translation(90035))
        self.setProperty("button16.label", translation(90415))
        self.setProperty("button17.label", translation(90416))

    # ─── Cast ─────────────────────────────────────────────────────────────────

    def fetch_cast(self):
        if not self.tmdb_id:
            return
        try:
            path = "movie_credits" if self.media_type == "movie" else "tv_credits"
            data = tmdb_get(path, {"id": self.tmdb_id})

            if data and hasattr(data, "cast"):
                castlist = self.getControlList(self.cast_list_id)
                castlist.reset()
                for actor in data.cast[:30]:
                    li = xbmcgui.ListItem(label=actor.get("name", ""))
                    li.setProperty("name", actor.get("name", ""))
                    li.setProperty("role", actor.get("character", ""))
                    li.setProperty("id", str(actor.get("id", "")))

                    profile_path = actor.get("profile_path")
                    if profile_path:
                        thumb = f"https://image.tmdb.org/t/p/w300{profile_path}"
                        li.setArt({"thumb": thumb, "icon": thumb})
                        li.setProperty("thumbnail", thumb)

                    castlist.addItem(li)
                self.setProperty("cast.number", f"({len(data.cast)})")
        except Exception as e:
            kodilog(f"Error fetching cast: {e}")

    # ─── Recommended (2051) ───────────────────────────────────────────────────

    def fetch_recommended(self):
        if not self.tmdb_id:
            return
        try:
            path = "movie_recommendations" if self.media_type == "movie" else "tv_recommendations"
            data = tmdb_get(path, {"id": self.tmdb_id, "page": 1})
            self.populate_media_list(self.recommended_list_id, data, "recommended.number")
        except Exception as e:
            kodilog(f"Error fetching recommended: {e}")

    # ─── Similar / More Like This (2052) ──────────────────────────────────────

    def fetch_similar(self):
        if not self.tmdb_id:
            return
        try:
            path = "movie_similar" if self.media_type == "movie" else "tv_similar"
            data = tmdb_get(path, {"id": self.tmdb_id, "page": 1})
            self.populate_media_list(self.similar_list_id, data, "more_like_this.number")
        except Exception as e:
            kodilog(f"Error fetching similar: {e}")

    # ─── AI Similar (2053) — uses recommendations page 2 ─────────────────────

    def fetch_ai_similar(self):
        if not self.tmdb_id:
            return
        path = "movie_recommendations" if self.media_type == "movie" else "tv_recommendations"
        data = tmdb_get(path, {"id": self.tmdb_id, "page": 2})
        self.populate_media_list(self.ai_similar_list_id, data, "ai_similar.number")

    # ─── Shared media list populator ──────────────────────────────────────────

    def populate_media_list(self, list_id, tmdb_data, count_property):
        if not tmdb_data:
            return
        try:
            items = []
            if hasattr(tmdb_data, "results"):
                items = tmdb_data.results[:20] if tmdb_data.results else []
            elif hasattr(tmdb_data, "_obj_list") and tmdb_data._obj_list:
                items = tmdb_data._obj_list[:20]
            elif isinstance(tmdb_data, list):
                items = tmdb_data[:20]

            if not items:
                return

            media_list = self.getControlList(list_id)
            media_list.reset()

            for item in items:
                title = item.get("title", "") or item.get("name", "")
                li = xbmcgui.ListItem(label=title)
                li.setProperty("name", title)
                li.setProperty("id", str(item.get("id", "")))
                li.setProperty("media_type", item.get("media_type", self.media_type))

                # Extra info for labels in skin
                release = item.get("release_date", "") or item.get("first_air_date", "")
                if release:
                    li.setProperty("release_date", str(release)[:4])
                vote = item.get("vote_average")
                if vote:
                    li.setProperty("vote_average", f"{float(vote):.1f}")

                poster_path = item.get("poster_path")
                if poster_path:
                    thumb = f"https://image.tmdb.org/t/p/w300{poster_path}"
                    li.setArt({"thumb": thumb, "icon": thumb})
                    li.setProperty("thumbnail", thumb)

                media_list.addItem(li)

            self.setProperty(count_property, f"({len(items)})")
        except Exception as e:
            kodilog(f"Error populating media list {list_id}: {e}")

    # ─── YouTube Videos (2060) ────────────────────────────────────────────────

    def _populate_youtube_videos(self):
        data = self._tmdb_data
        if not data:
            return

        videos = getattr(data, "videos", None)
        if not videos:
            return

        results = getattr(videos, "results", None)
        if not results:
            return

        video_items = []
        for v in results:
            site = v.get("site", "")
            if str(site).lower() != "youtube":
                continue
            video_items.append(v)

        if not video_items:
            return

        vid_list = self.getControlList(self.youtube_list_id)
        vid_list.reset()
        for v in video_items[:20]:
            name = v.get("name", "")
            key = v.get("key", "")
            vtype = v.get("type", "")
            li = xbmcgui.ListItem(label=name)
            li.setProperty("name", name)
            li.setProperty("key", key)
            li.setProperty("video_type", vtype)
            thumb = f"https://img.youtube.com/vi/{key}/mqdefault.jpg"
            li.setProperty("thumbnail", thumb)
            li.setArt({"thumb": thumb, "icon": thumb})
            vid_list.addItem(li)

        self.setProperty("youtube_videos.number", f"({len(video_items[:20])})")

    # ─── Collection (2064, movie only) ────────────────────────────────────────

    def _populate_collection(self):
        if self.media_type != "movie":
            return

        data = self._tmdb_data
        if not data:
            return

        collection = getattr(data, "belongs_to_collection", None)
        if not collection:
            return

        collection_id = collection.get("id")
        collection_name = collection.get("name", "")
        collection_poster = collection.get("poster_path", "")

        if not collection_id:
            return

        self.setProperty("more_from_collection.name", collection_name)
        if collection_poster:
            self.setProperty(
                "more_from_collection.poster",
                f"https://image.tmdb.org/t/p/w300{collection_poster}",
            )

        # Fetch collection details
        col_data = tmdb_get("collection_details", collection_id)
        if not col_data:
            return

        parts = getattr(col_data, "parts", None)
        if not parts:
            return

        col_list = self.getControlList(self.collection_list_id)
        col_list.reset()

        count = 0
        for part in parts:
            title = part.get("title", "") or part.get("name", "")
            li = xbmcgui.ListItem(label=title)
            li.setProperty("name", title)
            li.setProperty("id", str(part.get("id", "")))
            li.setProperty("media_type", "movie")

            release = part.get("release_date", "")
            if release:
                li.setProperty("release_date", str(release)[:4])
            vote = part.get("vote_average")
            if vote:
                li.setProperty("vote_average", f"{float(vote):.1f}")

            poster_path = part.get("poster_path")
            if poster_path:
                thumb = f"https://image.tmdb.org/t/p/w300{poster_path}"
                li.setArt({"thumb": thumb, "icon": thumb})
                li.setProperty("thumbnail", thumb)

            col_list.addItem(li)
            count += 1

        self.setProperty("more_from_collection.number", f"({count})")

    # ─── More from Year (2061) ────────────────────────────────────────────────

    def _populate_more_from_year(self):
        data = self._tmdb_data
        if not data:
            return

        if self.media_type == "movie":
            release_date = getattr(data, "release_date", "")
        else:
            release_date = getattr(data, "first_air_date", "")

        if not release_date or len(str(release_date)) < 4:
            return

        year = str(release_date)[:4]

        if self.media_type == "movie":
            discover_data = tmdb_get(
                "discover_movie",
                {
                    "primary_release_year": year,
                    "sort_by": "vote_count.desc",
                    "page": 1,
                },
            )
        else:
            discover_data = tmdb_get(
                "discover_tv",
                {
                    "first_air_date_year": year,
                    "sort_by": "vote_count.desc",
                    "page": 1,
                },
            )

        if discover_data:
            # Filter out the current item
            self._filter_and_populate(
                self.more_year_list_id, discover_data, "more_from_year.number"
            )

    # ─── More from Genres (2062) ──────────────────────────────────────────────

    def _populate_more_from_genres(self):
        data = self._tmdb_data
        if not data:
            return

        genres = getattr(data, "genres", None)
        if not genres:
            return

        genre_ids = []
        for g in genres:
            gid = g.get("id") if hasattr(g, "get") else getattr(g, "id", None)
            if gid:
                genre_ids.append(str(gid))

        if not genre_ids:
            return

        genre_str = ",".join(genre_ids[:3])

        if self.media_type == "movie":
            discover_data = tmdb_get(
                "discover_movie",
                {
                    "with_genres": genre_str,
                    "sort_by": "vote_count.desc",
                    "page": 1,
                },
            )
        else:
            discover_data = tmdb_get(
                "discover_tv",
                {
                    "with_genres": genre_str,
                    "sort_by": "vote_count.desc",
                    "page": 1,
                },
            )

        if discover_data:
            self._filter_and_populate(
                self.more_genres_list_id, discover_data, "more_from_genres.number"
            )

    # ─── More from Networks (2063, TV only) ───────────────────────────────────

    def _populate_more_from_networks(self):
        if self.media_type != "tv":
            return

        data = self._tmdb_data
        if not data:
            return

        networks = getattr(data, "networks", None)
        if not networks:
            return

        network_ids = []
        for n in networks:
            nid = n.get("id") if hasattr(n, "get") else getattr(n, "id", None)
            if nid:
                network_ids.append(str(nid))

        if not network_ids:
            return

        network_str = "|".join(network_ids[:3])

        discover_data = tmdb_get(
            "discover_tv",
            {
                "with_networks": network_str,
                "sort_by": "vote_count.desc",
                "page": 1,
            },
        )

        if discover_data:
            self._filter_and_populate(
                self.more_networks_list_id, discover_data, "more_from_networks.number"
            )

    def _filter_and_populate(self, list_id, tmdb_data, count_property):
        """Populate a media list, filtering out the current item."""
        if not tmdb_data or not hasattr(tmdb_data, "results"):
            return

        results = []
        for item in tmdb_data.results:
            item_id = item.get("id")
            if str(item_id) != str(self.tmdb_id):
                results.append(item)
            if len(results) >= 20:
                break

        if not results:
            return

        media_list = self.getControlList(list_id)
        media_list.reset()

        for item in results:
            title = item.get("title", "") or item.get("name", "")
            li = xbmcgui.ListItem(label=title)
            li.setProperty("name", title)
            li.setProperty("id", str(item.get("id", "")))
            li.setProperty("media_type", item.get("media_type", self.media_type))

            release = item.get("release_date", "") or item.get("first_air_date", "")
            if release:
                li.setProperty("release_date", str(release)[:4])
            vote = item.get("vote_average")
            if vote:
                li.setProperty("vote_average", f"{float(vote):.1f}")

            poster_path = item.get("poster_path")
            if poster_path:
                thumb = f"https://image.tmdb.org/t/p/w300{poster_path}"
                li.setArt({"thumb": thumb, "icon": thumb})
                li.setProperty("thumbnail", thumb)

            media_list.addItem(li)

        self.setProperty(count_property, f"({len(results)})")

    # ─── IMDb/TMDB Reviews, Trivia, Blunders, Comments ────────────────────────

    def fetch_imdb_data(self):
        # Wait up to 5 seconds for fetch_details_and_artwork to set self.imdb_id
        self._details_ready.wait(timeout=5)

        if not self.imdb_id:
            # Still try TMDB reviews and Trakt comments even without IMDb ID
            self._fetch_tmdb_reviews()
            self._fetch_trakt_comments()
            return

        # Fetch all IMDb extras in a single GraphQL call
        try:
            extras = get_imdb_extras(self.imdb_id)

            # 1. IMDb Reviews
            try:
                imdb_reviews = extras.get("reviews", [])
                if imdb_reviews:
                    self._populate_text_panel(
                        self.reviews_list_id, imdb_reviews, "imdb_reviews.number"
                    )
            except Exception as e:
                kodilog(f"Error populating IMDb reviews: {e}")

            # 2. IMDb Trivia
            try:
                trivia = extras.get("trivia", [])
                self._populate_text_panel(self.trivia_list_id, trivia, "imdb_trivia.number")
            except Exception as e:
                kodilog(f"Error populating trivia: {e}")

            # 3. IMDb Goofs / Blunders
            try:
                blunders = extras.get("blunders", [])
                self._populate_text_panel(self.blunders_list_id, blunders, "imdb_blunders.number")
            except Exception as e:
                kodilog(f"Error populating blunders: {e}")

            # 4. IMDb Parental Guide
            try:
                guide_items = extras.get("parentsguide", [])
                guide_texts = []
                for item in guide_items:
                    header = f"[B]{item['title']}[/B]"
                    if item.get("ranking"):
                        header += f" — {item['ranking']}"
                    if item.get("content"):
                        guide_texts.append(f"{header}[CR][CR]{item['content']}")
                    else:
                        guide_texts.append(header)
                self._populate_text_panel(
                    self.parental_guide_list_id,
                    guide_texts,
                    "imdb_parentsguide.number",
                )
            except Exception as e:
                kodilog(f"Error populating parental guide: {e}")

        except Exception as e:
            kodilog(f"Error fetching IMDb GraphQL extras: {e}")

        # 5. Trakt Comments (keep as separate source)
        self._fetch_trakt_comments()

    def _fetch_tmdb_reviews(self):
        try:
            path = "movie_reviews" if self.media_type == "movie" else "tv_reviews"
            reviews_data = tmdb_get(path, {"id": self.tmdb_id, "page": 1})
            reviews_list = []
            if reviews_data:
                results = None
                if hasattr(reviews_data, "results"):
                    results = reviews_data.results
                elif hasattr(reviews_data, "_obj_list"):
                    results = reviews_data._obj_list

                if results:
                    for rev in results:
                        content = getattr(rev, "content", "") or rev.get("content", "")
                        author = getattr(rev, "author", "") or rev.get("author", "Unknown")
                        if content:
                            reviews_list.append(f"[B]{author}[/B]\n{content}")
            self._populate_text_panel(self.reviews_list_id, reviews_list, "imdb_reviews.number")
        except Exception as e:
            kodilog(f"Error fetching TMDB reviews: {e}")

    def _fetch_trakt_comments(self):
        try:
            from lib.api.trakt.trakt import TraktAPI

            trakt_comments_data = TraktAPI().lists.trakt_comments(
                self.media_type, self.tmdb_id, sort_type="likes", page_no=1
            )
            comments_list = []
            if isinstance(trakt_comments_data, tuple):
                trakt_comments_data = trakt_comments_data[0]

            if trakt_comments_data and isinstance(trakt_comments_data, list):
                for comment in trakt_comments_data:
                    text = comment.get("comment", "")
                    user = comment.get("user", {}).get("username", "Unknown")
                    if text:
                        comments_list.append(f"[B]{user}[/B]\n{text}")
            self._populate_text_panel(self.comments_list_id, comments_list, "trakt_comments.number")
        except Exception as e:
            kodilog(f"Error fetching trakt comments: {e}")
            self._populate_text_panel(self.comments_list_id, [], "trakt_comments.number")

    def _populate_text_panel(self, list_id, string_list, count_property):
        try:
            panel = self.getControlList(list_id)
            panel.reset()
            if string_list:
                for text_item in string_list[:20]:
                    li = xbmcgui.ListItem(label="")
                    li.setProperty("text", text_item)
                    panel.addItem(li)
            self.setProperty(count_property, f"({len(string_list)})")
        except Exception as e:
            kodilog(f"Error populating text panel {list_id}: {e}")

    # ─── Action Handling ──────────────────────────────────────────────────────

    def handle_action(self, action_id, control_id=None):
        if action_id == 7:  # Select/Click
            self._handle_click(control_id)

    def _handle_click(self, control_id):
        # Buttons 10-17
        if control_id == 10:  # Play
            mode = "movies" if self.media_type == "movie" else "tv"
            tv_data = self.item_information.get("tv_data", "{}")

            self.close()
            execute_builtin(
                f"PlayMedia({build_url('search', query=self.title, mode=mode, ids=json.dumps({'tmdb_id': self.tmdb_id, 'imdb_id': self.imdb_id}), tv_data=tv_data)})"
            )

        elif control_id == 11:  # Trailer
            self.close()
            execute_builtin(
                f"PlayMedia({build_url('play_trailer', tmdb_id=self.tmdb_id, media_type=self.media_type, title=self.title)})"
            )

        elif control_id == 15:  # Watchlist
            try:
                from lib.api.trakt.trakt import TraktAPI

                TraktAPI().lists.add_to_watchlist(self.media_type, {"tmdb": self.tmdb_id})
                notification(translation(90409))
            except Exception as e:
                kodilog(f"Error modifying trakt watchlist: {e}")
                notification(translation(90410))

        elif control_id == 16:  # Watched
            try:
                from lib.api.trakt.trakt import TraktAPI

                if self.media_type == "movie":
                    TraktAPI().lists.mark_as_watched("movie", None, None, {"tmdb": self.tmdb_id})
                else:
                    TraktAPI().lists.mark_as_watched("show", None, None, {"tmdb": self.tmdb_id})
                notification(translation(90411))
            except Exception as e:
                kodilog(f"Error marking watched on trakt: {e}")
                notification(translation(90412))

        elif control_id == 17:  # Refresh
            notification(translation(90402))
            self.close()

        # ── YouTube video click ──
        elif control_id == self.youtube_list_id:
            try:
                item = self.getControlList(self.youtube_list_id).getSelectedItem()
                key = item.getProperty("key")
                if key:
                    execute_builtin(
                        f"RunPlugin(plugin://plugin.video.youtube/play/?video_id={key})"
                    )
            except Exception as e:
                kodilog(f"Error playing YouTube video: {e}")

        # ── Cast click ──
        elif control_id == self.cast_list_id:
            item = self.getControlList(self.cast_list_id).getSelectedItem()
            person_id = item.getProperty("id")
            if person_id:
                from lib.gui.actor_info_window import ActorInfoWindow

                actor_window = ActorInfoWindow(
                    "actor_info.xml",
                    ADDON_PATH,
                    person_id=person_id,
                )
                actor_window.doModal()

        # ── Media list clicks (recommended, similar, ai_similar, collection, more_from_*) ──
        elif control_id in [
            self.recommended_list_id,
            self.similar_list_id,
            self.ai_similar_list_id,
            self.collection_list_id,
            self.more_year_list_id,
            self.more_genres_list_id,
            self.more_networks_list_id,
        ]:
            item = self.getControlList(control_id).getSelectedItem()
            tmdb_id = item.getProperty("id")
            media_type = item.getProperty("media_type")
            title = item.getProperty("name")
            if tmdb_id:
                mode = "movies" if media_type == "movie" else "tv"
                execute_builtin(
                    f"RunPlugin(plugin://plugin.video.jacktook/?action=extras&id={tmdb_id}&media_type={media_type}&title={title})"
                )
                self.close()

        # ── Text list clicks (reviews, comments, trivia, blunders, parental guide) ──
        elif control_id in [
            self.reviews_list_id,
            self.comments_list_id,
            self.trivia_list_id,
            self.blunders_list_id,
            self.parental_guide_list_id,
        ]:
            item = self.getControlList(control_id).getSelectedItem()
            text = item.getProperty("text")
            if text:
                # Remove markdown formatting for the text viewer
                clean_text = (
                    text.replace("[B]", "")
                    .replace("[/B]", "")
                    .replace("[I]", "")
                    .replace("[/I]", "")
                )

                heading = translation(90632)
                if control_id == self.reviews_list_id:
                    heading = translation(90633)
                elif control_id == self.comments_list_id:
                    heading = translation(90634)
                elif control_id == self.trivia_list_id:
                    heading = translation(90635)
                elif control_id == self.blunders_list_id:
                    heading = translation(90636)
                elif control_id == self.parental_guide_list_id:
                    heading = translation(90637)

                xbmcgui.Dialog().textviewer(heading, clean_text)
