import sys
import xbmc
import xbmcgui
import xbmcplugin
import xbmcaddon
import xbmcvfs
import urllib.parse
import requests
import json
import time
import tempfile
import os
import uuid
import re
from urllib.request import urlopen
from urllib.parse import quote, unquote, parse_qs
import random
import xml.etree.ElementTree as ET
from typing import Dict

xbmc.executebuiltin('Action(SubtitleDelayMinus)')

ADDON = xbmcaddon.Addon()
ADDON_ID = ADDON.getAddonInfo('id')
ADDON_NAME = ADDON.getAddonInfo('name')
ADDON_VERSION = ADDON.getAddonInfo('version')
ADDON_PATH = ADDON.getAddonInfo('path')

TMDB_API_KEY = "a46c50a0ccb1bafe2b15665df7fad7e1"
TMDB_BASE_URL = "https://api.themoviedb.org/3"
IMAGE_BASE_URL = "https://image.tmdb.org/t/p/"
STREAM_API_URL = "https://tmkt-api-production.up.railway.app/debug/stream"
SUBTITLE_API_URL = "https://sub.wyzie.ru/search"

POSTER_SIZE = "w500"
BACKDROP_SIZE = "w1280"

ADDON_DATA_PATH = xbmcvfs.translatePath(f"special://profile/addon_data/{ADDON_ID}")
CLIENT_ID_FILE = os.path.join(ADDON_DATA_PATH, "client_id.txt")
SUBTITLE_CACHE_FILE = os.path.join(ADDON_DATA_PATH, "subtitle_cache.json")
WATCH_HISTORY_FILE = os.path.join(ADDON_DATA_PATH, "watch_history.json")

PAID_API_CHECK_URL = "https://tmkt-api-production.up.railway.app/debug/validate_key"
PAID_CACHE_FILE = xbmcvfs.translatePath(f"special://profile/addon_data/{ADDON_ID}/paid_cache.json")

def is_paid_user(force_refresh=False):
    log(f"is_paid_user() called with force_refresh={force_refresh}", xbmc.LOGDEBUG)
    
    api_key = ADDON.getSetting("paid_api_key")
    if not api_key:
        log("No API key found in settings", xbmc.LOGDEBUG)
        if xbmcvfs.exists(PAID_CACHE_FILE):
            try:
                xbmcvfs.delete(PAID_CACHE_FILE)
                log("Cleared paid cache (no API key)", xbmc.LOGDEBUG)
            except:
                pass
        return False

    api_key = api_key.strip()
    log(f"Using API key: {api_key[:8]}...", xbmc.LOGDEBUG)
    
    if not force_refresh and xbmcvfs.exists(PAID_CACHE_FILE):
        try:
            with xbmcvfs.File(PAID_CACHE_FILE, 'r') as f:
                cache_data = json.load(f)
                
            cache_age = time.time() - cache_data.get("timestamp", 0)
            cache_valid = cache_age < 3600
            
            key_matches = cache_data.get("api_key") == api_key
            
            if cache_valid and key_matches:
                is_paid = cache_data.get("is_paid", False)
                log(f"Using cached value (age: {cache_age:.1f}s): is_paid={is_paid}", xbmc.LOGDEBUG)
                return is_paid
            else:
                log(f"Cache invalid or expired (age: {cache_age:.1f}s, key_matches: {key_matches})", xbmc.LOGDEBUG)
        except Exception as e:
            log(f"Error reading cache: {str(e)}", xbmc.LOGDEBUG)
    
    current_client_id = get_client_id()
    log(f"Validating API key with backend (client_id: {current_client_id[:8]}...)", xbmc.LOGDEBUG)
    
    is_paid = False
    http_status = 0
    response_text = ""
    
    try:
        params = {
            "api_key": api_key,
            "client_id": current_client_id
        }
        
        resp = requests.get(PAID_API_CHECK_URL, params=params, timeout=10)
        http_status = resp.status_code
        response_text = resp.text[:200]
        
        log(f"Response status: {http_status}", xbmc.LOGDEBUG)
        log(f"Response: {response_text}", xbmc.LOGDEBUG)
        
        if resp.status_code == 200:
            result = resp.json()
            log(f"Parsed JSON: {result}", xbmc.LOGDEBUG)
            
            if isinstance(result, dict):
                is_paid = result.get("paid", False) or result.get("plan") == "paid"
                
                if not is_paid and "error" not in result:
                    is_paid = True
                
                if is_paid:
                    log(f"API key is VALID and PAID", xbmc.LOGDEBUG)
                else:
                    log(f"API key validation failed", xbmc.LOGDEBUG)
            else:
                log(f"Response is not a JSON object: {result}", xbmc.LOGERROR)
                is_paid = False
        elif resp.status_code == 401:
            log(f"API key rejected (401)", xbmc.LOGDEBUG)
            is_paid = False
        else:
            log(f"HTTP error: {http_status}", xbmc.LOGERROR)
            if xbmcvfs.exists(PAID_CACHE_FILE):
                try:
                    with xbmcvfs.File(PAID_CACHE_FILE, 'r') as f:
                        cache_data = json.load(f)
                        if cache_data.get("api_key") == api_key:
                            is_paid = cache_data.get("is_paid", False)
                            log(f"Using cached value due to network error: {is_paid}", xbmc.LOGDEBUG)
                except:
                    pass
            is_paid = False
            
    except requests.exceptions.Timeout:
        log(f"Request timeout", xbmc.LOGERROR)
        if xbmcvfs.exists(PAID_CACHE_FILE):
            try:
                with xbmcvfs.File(PAID_CACHE_FILE, 'r') as f:
                    cache_data = json.load(f)
                    if cache_data.get("api_key") == api_key:
                        is_paid = cache_data.get("is_paid", False)
                        log(f"Using cached value due to timeout: {is_paid}", xbmc.LOGDEBUG)
            except:
                pass
        is_paid = False
    except requests.exceptions.ConnectionError:
        log(f"Connection error", xbmc.LOGERROR)
        if xbmcvfs.exists(PAID_CACHE_FILE):
            try:
                with xbmcvfs.File(PAID_CACHE_FILE, 'r') as f:
                    cache_data = json.load(f)
                    if cache_data.get("api_key") == api_key:
                        is_paid = cache_data.get("is_paid", False)
                        log(f"Using cached value due to connection error: {is_paid}", xbmc.LOGDEBUG)
            except:
                pass
        is_paid = False
    except Exception as e:
        log(f"Unexpected error: {str(e)}", xbmc.LOGERROR)
        is_paid = False
    
    log(f"Saving to cache: is_paid={is_paid}", xbmc.LOGDEBUG)
    try:
        folder = xbmcvfs.translatePath(f"special://profile/addon_data/{ADDON_ID}")
        if not xbmcvfs.exists(folder):
            xbmcvfs.mkdirs(folder)
            log(f"Created folder: {folder}", xbmc.LOGDEBUG)
        
        cache_data = {
            "api_key": api_key,
            "is_paid": is_paid,
            "timestamp": time.time(),
            "client_id": current_client_id,
            "last_checked": time.strftime("%Y-%m-%d %H:%M:%S"),
            "http_status": http_status
        }
        
        with xbmcvfs.File(PAID_CACHE_FILE, 'w') as f:
            json.dump(cache_data, f)
            log(f"Cache saved: {PAID_CACHE_FILE}", xbmc.LOGDEBUG)
            
    except Exception as e:
        log(f"Failed to save cache: {str(e)}", xbmc.LOGERROR)
    
    return is_paid

def get_subtitle_cache():
    """Load subtitle cache from file"""
    if xbmcvfs.exists(SUBTITLE_CACHE_FILE):
        try:
            with xbmcvfs.File(SUBTITLE_CACHE_FILE, 'r') as f:
                return json.load(f)
        except Exception as e:
            log(f"Error loading subtitle cache: {e}", xbmc.LOGDEBUG)
    return {}

def save_subtitle_cache(cache):
    """Save subtitle cache to file"""
    try:
        folder = xbmcvfs.translatePath(f"special://profile/addon_data/{ADDON_ID}")
        if not xbmcvfs.exists(folder):
            xbmcvfs.mkdirs(folder)
        
        with xbmcvfs.File(SUBTITLE_CACHE_FILE, 'w') as f:
            json.dump(cache, f)
    except Exception as e:
        log(f"Error saving subtitle cache: {e}", xbmc.LOGDEBUG)

def validate_subtitle_content(content):
    """Simplified validation - just check if there's any content"""
    if not content or not content.strip():
        return False
    
    if len(content.strip()) < 10:
        return False
    
    content_lower = content.lower()
    if "no subtitles" in content_lower or "404" in content or "not found" in content_lower:
        return False

    if not content.startswith('<!DOCTYPE') and not content.startswith('<html'):
        return True
    
    return False

def validate_subtitle_url(subtitle_url):
    """Check if subtitle URL returns valid content with actual subtitles"""
    try:
        response = requests.get(subtitle_url, timeout=5)
        if response.status_code == 200 and response.text.strip():
            content = response.text
            
            if validate_subtitle_content(content):
                log(f"Valid subtitle found at {subtitle_url}", xbmc.LOGDEBUG)
                return True
            else:
                log(f"Subtitle URL {subtitle_url} returned content but no valid subtitles", xbmc.LOGDEBUG)
                return False
    except Exception as e:
        log(f"Error validating subtitle URL {subtitle_url}: {e}", xbmc.LOGDEBUG)
    return False

def get_valid_subtitles(imdb_id, media_type="movie", season=None, episode=None):
    """Get subtitles from API - very simple version"""
    log(f"Getting subtitles for: {imdb_id} {media_type}", xbmc.LOGDEBUG)
    
    try:
        if media_type == "movie":
            url = f"{SUBTITLE_API_URL}?id={imdb_id}&format=srt"
        else:
            if season and episode:
                url = f"{SUBTITLE_API_URL}?id={imdb_id}&season={season}&episode={episode}&format=srt"
            else:
                url = f"{SUBTITLE_API_URL}?id={imdb_id}&format=srt"
        
        log(f"Requesting: {url}", xbmc.LOGDEBUG)
        response = requests.get(url, timeout=15)
        
        if response.status_code == 200:
            subtitles_data = response.json()
            log(f"Got subtitle data: {type(subtitles_data)}", xbmc.LOGDEBUG)
            
            if isinstance(subtitles_data, dict):
                subtitles_data = [subtitles_data]
            
            if isinstance(subtitles_data, list):
                valid_subs = []
                for sub in subtitles_data:
                    if isinstance(sub, dict) and sub.get("url"):
                        valid_subs.append(sub)
                
                log(f"Found {len(valid_subs)} subtitles with URLs", xbmc.LOGDEBUG)
                
                language_seen = set()
                filtered = []
                for sub in valid_subs:
                    lang = sub.get("language", "unknown").lower()
                    lang_code = lang[:2] if len(lang) >= 2 else lang
                    
                    if lang_code not in language_seen:
                        language_seen.add(lang_code)
                        filtered.append(sub)
                
                log(f"Returning {len(filtered)} subtitles (1 per language)", xbmc.LOGDEBUG)
                return filtered
        
        log(f"No subtitles found or API error: {response.status_code}", xbmc.LOGDEBUG)
        return []
            
    except Exception as e:
        log(f"Error getting subtitles: {str(e)}", xbmc.LOGDEBUG)
        return []

TV_WATCH_PROGRESS_FILE = os.path.join(ADDON_DATA_PATH, "tv_watch_progress.json")
TRAKT_CLIENT_ID = "5d6cc5885f09bab6380eec63405093a3b350e2134615cbc61e3b07b89bc87f65"
TRAKT_CLIENT_SECRET = "7f2b40f8b5b5edd9e0eb916c69772b49735b4d0fde0af33b469a5bd297f6a22e"
TRAKT_TOKEN_FILE = os.path.join(ADDON_DATA_PATH, "trakt_token.json")

def trakt_watchlist(page=1):
    """Display Trakt watchlist with pagination - Available to paid users only"""
    if not is_paid_user():
        xbmcgui.Dialog().notification(ADDON_NAME, "Paid feature only", xbmcgui.NOTIFICATION_ERROR)
        return
    
    headers = get_trakt_headers()
    if not headers:
        xbmcgui.Dialog().notification(ADDON_NAME, "Link Trakt account first", xbmcgui.NOTIFICATION_ERROR)
        return

    handle = int(sys.argv[1])
    tmdb = TMDBClient()
    
    try:
        limit = 20 
        url = f"https://api.trakt.tv/users/me/watchlist?limit={limit}&page={page}"
        log(f"Fetching Trakt watchlist page {page} from: {url}", xbmc.LOGDEBUG)
        
        response = requests.get(url, headers=headers, timeout=15)
        
        if response.status_code == 401 or response.status_code == 403:
            xbmcgui.Dialog().notification(ADDON_NAME, "Trakt token expired. Please relink", xbmcgui.NOTIFICATION_ERROR)
            if xbmcvfs.exists(TRAKT_TOKEN_FILE):
                xbmcvfs.delete(TRAKT_TOKEN_FILE)
            return
            
        response.raise_for_status()
        watchlist_items = response.json()
        
        if not watchlist_items:
            if page == 1:
                xbmcgui.Dialog().notification(ADDON_NAME, "Watchlist is empty", xbmcgui.NOTIFICATION_INFO)
            xbmcplugin.endOfDirectory(handle)
            return
        
        movies = []
        tv_shows = []
        
        for item in watchlist_items:
            media_type = item.get('type', '')
            if media_type == 'movie':
                movies.append(item)
            elif media_type == 'show':
                tv_shows.append(item)
        
        page_header = xbmcgui.ListItem(f"=== WATCHLIST PAGE {page} ===")
        page_header.setArt({'icon': 'DefaultFolder.png'})
        page_header.setInfo('video', {'title': f"Page {page}"})
        xbmcplugin.addDirectoryItem(handle, "", page_header, isFolder=False)
        
        if tv_shows:
            for item in tv_shows:
                show = item.get('show', {})
                if not show:
                    continue
                    
                title = show.get('title', 'Unknown')
                year_str = str(show.get('year', ''))
                tmdb_id = show.get('ids', {}).get('tmdb')
                tvdb_id = show.get('ids', {}).get('tvdb')
                
                try:
                    year_int = int(year_str) if year_str and year_str.isdigit() else 0
                except:
                    year_int = 0
                
                label = f"{title} ({year_str})" if year_str and year_str != '0' else title
                li = xbmcgui.ListItem(label)
                
                poster = ""
                fanart = ""
                if tmdb_id:
                    try:
                        tmdb_details = tmdb.get_tv_details(tmdb_id)
                        if tmdb_details:
                            poster = build_image_url(tmdb_details.get("poster_path"), POSTER_SIZE)
                            fanart = build_image_url(tmdb_details.get("backdrop_path"), BACKDROP_SIZE)
                    except Exception as e:
                        log(f"Error getting TMDB details for {tmdb_id}: {e}", xbmc.LOGDEBUG)
                        pass
                
                li.setArt({
                    'icon': poster or 'DefaultVideo.png',
                    'thumb': poster or 'DefaultVideo.png',
                    'poster': poster or 'DefaultVideo.png',
                    'fanart': fanart or ADDON_PATH + "/fanart.jpg"
                })
                
                info = {
                    'title': title,
                    'year': year_int,
                    'tvshowtitle': title,
                    'mediatype': 'tvshow'
                }
                li.setInfo('video', info)
                
                context_menu_items = []
                
                if tmdb_id:
                    details_url = get_url(action="tv_details", id=tmdb_id, from_watchlist="true")
                    
                    if tvdb_id:
                        remove_url = get_url(action="trakt_remove_tv_watchlist", tvdb_id=tvdb_id)
                        context_menu_items.append(("Remove from Watchlist", f"RunPlugin({remove_url})"))
                    
                    li.addContextMenuItems(context_menu_items)
                    
                    xbmcplugin.addDirectoryItem(handle, details_url, li, isFolder=True)
        
        if movies:
            for item in movies:
                movie = item.get('movie', {})
                if not movie:
                    continue
                    
                title = movie.get('title', 'Unknown')
                year_str = str(movie.get('year', ''))
                tmdb_id = movie.get('ids', {}).get('tmdb')
                imdb_id = movie.get('ids', {}).get('imdb', '')
                
                try:
                    year_int = int(year_str) if year_str and year_str.isdigit() else 0
                except:
                    year_int = 0
                
                label = f"{title} ({year_str})" if year_str and year_str != '0' else title
                li = xbmcgui.ListItem(label)
                
                poster = ""
                fanart = ""
                plot = ""
                rating = 0.0
                
                if tmdb_id:
                    try:
                        tmdb_details = tmdb.get_movie_details(tmdb_id)
                        if tmdb_details:
                            poster = build_image_url(tmdb_details.get("poster_path"), POSTER_SIZE)
                            fanart = build_image_url(tmdb_details.get("backdrop_path"), BACKDROP_SIZE)
                            plot = tmdb_details.get("overview", "")
                            rating = float(tmdb_details.get("vote_average", 0))
                    except Exception as e:
                        log(f"Error getting TMDB details for {tmdb_id}: {e}", xbmc.LOGDEBUG)
                        pass
                
                li.setArt({
                    'icon': poster or 'DefaultVideo.png',
                    'thumb': poster or 'DefaultVideo.png',
                    'poster': poster or 'DefaultVideo.png',
                    'fanart': fanart or ADDON_PATH + "/fanart.jpg"
                })
                
                info = {
                    'title': title,
                    'year': year_int,
                    'plot': plot,
                    'rating': rating,
                    'mediatype': 'movie'
                }
                li.setInfo('video', info)
                
                context_menu_items = []
                
                if imdb_id:
                    play_url = get_url(action="play_movie", ttid=imdb_id, title=title, from_watchlist="true")
                    context_menu_items.append(("Play", f"PlayMedia({play_url})"))
                    
                    if tmdb_id:
                        play_subs_url = get_url(action="play_movie_subs", ttid=imdb_id, title=title, from_watchlist="true")
                        context_menu_items.append(("Play with Subtitles", f"PlayMedia({play_subs_url})"))
                    
                    remove_url = get_url(action="trakt_remove_watchlist", imdb_id=imdb_id)
                    context_menu_items.append(("Remove from Watchlist", f"RunPlugin({remove_url})"))
                    
                    li.addContextMenuItems(context_menu_items)
                    
                    details_url = get_url(action="movie_details", id=tmdb_id if tmdb_id else 0)
                    xbmcplugin.addDirectoryItem(handle, details_url, li, isFolder=True)
        
        if len(watchlist_items) == limit:
            next_url = get_url(action="trakt_watchlist", page=page + 1)
            next_item = xbmcgui.ListItem(label="Next Page →")
            next_item.setArt({'icon': 'DefaultFolder.png'})
            next_item.setInfo('video', {'title': "Next Page"})
            xbmcplugin.addDirectoryItem(handle, next_url, next_item, isFolder=True)
        
        if page > 1:
            prev_url = get_url(action="trakt_watchlist", page=page - 1)
            prev_item = xbmcgui.ListItem(label="← Previous Page")
            prev_item.setArt({'icon': 'DefaultFolder.png'})
            prev_item.setInfo('video', {'title': "Previous Page"})
            xbmcplugin.addDirectoryItem(handle, prev_url, prev_item, isFolder=True)
        
        xbmcplugin.setContent(handle, 'videos')
        xbmcplugin.endOfDirectory(handle)
        
    except Exception as e:
        log(f"Trakt watchlist error: {str(e)}", xbmc.LOGERROR)
        xbmcgui.Dialog().notification(ADDON_NAME, f"Failed to load watchlist: {str(e)}", xbmc.LOGERROR)
        xbmcplugin.endOfDirectory(handle)


def save_trakt_token(token_data):
    try:
        with open(TRAKT_TOKEN_FILE, "w") as f:
            json.dump(token_data, f)
        if 'username' in token_data:
            ADDON.setSetting("trakt_username", token_data['username'])
    except Exception as e:
        log(f"Failed saving Trakt token: {e}", xbmc.LOGERROR)

def load_trakt_token():
    if xbmcvfs.exists(TRAKT_TOKEN_FILE):
        try:
            with open(TRAKT_TOKEN_FILE, "r") as f:
                return json.load(f)
        except Exception:
            return None
    return None

def exchange_trakt_code(code):
    url = "https://api.trakt.tv/oauth/token"
    payload = {
        "code": code,
        "client_id": TRAKT_CLIENT_ID,
        "client_secret": TRAKT_CLIENT_SECRET,
        "redirect_uri": "urn:ietf:wg:oauth:2.0:oob",
        "grant_type": "authorization_code"
    }
    try:
        resp = requests.post(url, json=payload, timeout=15)
        resp.raise_for_status()
        token_data = resp.json()
        save_trakt_token(token_data)
        return token_data
    except Exception as e:
        log(f"Trakt linking failed: {e}", xbmc.LOGERROR)
        return None

def get_trakt_headers():
    api_key = ADDON.getSetting("paid_api_key")
    if not api_key:
        return None
    
    if xbmcvfs.exists(PAID_CACHE_FILE):
        try:
            with xbmcvfs.File(PAID_CACHE_FILE, 'r') as f:
                cache_data = json.load(f)
                
            cache_age = time.time() - cache_data.get("timestamp", 0)
            key_matches = cache_data.get("api_key") == api_key.strip()
            
            if cache_age < 3600 and key_matches and cache_data.get("is_paid", False):
                token_data = load_trakt_token()
                if not token_data:
                    return None
                return {
                    "Authorization": f"Bearer {token_data['access_token']}",
                    "Content-Type": "application/json",
                    "trakt-api-version": "2",
                    "trakt-api-key": TRAKT_CLIENT_ID
                }
        except:
            pass
    
    if not is_paid_user():
        return None
    token_data = load_trakt_token()
    if not token_data:
        return None
    return {
        "Authorization": f"Bearer {token_data['access_token']}",
        "Content-Type": "application/json",
        "trakt-api-version": "2",
        "trakt-api-key": TRAKT_CLIENT_ID
    }

def trakt_add_tv_to_watchlist_simple(tvdb_id):
    if not is_paid_user():
        xbmcgui.Dialog().notification(ADDON_NAME, "Paid feature only", xbmcgui.NOTIFICATION_ERROR)
        return False
    
    headers = get_trakt_headers()
    if not headers:
        xbmcgui.Dialog().notification(ADDON_NAME, "Link Trakt first", xbmcgui.NOTIFICATION_ERROR)
        return False
    
    payload = {"shows": [{"ids": {"tvdb": tvdb_id}}]}
    url = "https://api.trakt.tv/sync/watchlist"
    try:
        resp = requests.post(url, headers=headers, json=payload, timeout=15)
        if resp.status_code in (200, 201):
            xbmcgui.Dialog().notification(ADDON_NAME, "Added to watchlist", xbmcgui.NOTIFICATION_INFO)
            return True
        else:
            log(f"Failed to add TV to watchlist: {resp.status_code} - {resp.text}", xbmc.LOGERROR)
            return False
    except Exception as e:
        log(f"Error adding TV to watchlist: {e}", xbmc.LOGERROR)
        return False

def trakt_remove_tv_from_watchlist_simple(tvdb_id):
    if not is_paid_user():
        return False
    
    headers = get_trakt_headers()
    if not headers:
        return False
    
    payload = {"shows": [{"ids": {"tvdb": tvdb_id}}]}
    url = "https://api.trakt.tv/sync/watchlist/remove"
    try:
        resp = requests.post(url, headers=headers, json=payload, timeout=15)
        if resp.status_code in (200, 201):
            log(f"Successfully removed TV show {tvdb_id} from watchlist", xbmc.LOGDEBUG)
            return True
        else:
            log(f"Failed to remove TV from watchlist: {resp.status_code} - {resp.text}", xbmc.LOGERROR)
            return False
    except Exception as e:
        log(f"Error removing TV from watchlist: {e}", xbmc.LOGERROR)
        return False

def is_tv_in_trakt_watchlist(tvdb_id):
    if not is_paid_user():
        return False
    
    headers = get_trakt_headers()
    if not headers:
        return False
    
    try:
        url = "https://api.trakt.tv/sync/watchlist/shows"
        resp = requests.get(url, headers=headers, timeout=15)
        if resp.status_code == 200:
            watchlist = resp.json()
            for item in watchlist:
                if item.get('show', {}).get('ids', {}).get('tvdb') == tvdb_id:
                    return True
    except Exception as e:
        log(f"Error checking TV watchlist: {e}", xbmc.LOGERROR)
    
    return False

def trakt_add_to_watchlist_simple(imdb_id=None, tvdb_id=None):
    if not is_paid_user():
        xbmcgui.Dialog().notification(ADDON_NAME, "Paid feature only", xbmcgui.NOTIFICATION_ERROR)
        return False
    
    headers = get_trakt_headers()
    if not headers:
        xbmcgui.Dialog().notification(ADDON_NAME, "Link Trakt first", xbmcgui.NOTIFICATION_ERROR)
        return False
    
    payload = {}
    
    if imdb_id:
        payload["movies"] = [{"ids": {"imdb": imdb_id}}]
    elif tvdb_id:
        payload["shows"] = [{"ids": {"tvdb": tvdb_id}}]
    else:
        return False
    
    url = "https://api.trakt.tv/sync/watchlist"
    try:
        resp = requests.post(url, headers=headers, json=payload, timeout=15)
        if resp.status_code in (200, 201):
            item_type = "movie" if imdb_id else "TV show"
            xbmcgui.Dialog().notification(ADDON_NAME, f"Added {item_type} to watchlist", xbmcgui.NOTIFICATION_INFO)
            return True
        else:
            log(f"Failed to add to watchlist: {resp.status_code} - {resp.text}", xbmc.LOGERROR)
            return False
    except Exception as e:
        log(f"Error adding to watchlist: {e}", xbmc.LOGERROR)
        return False

def trakt_remove_from_watchlist_simple(imdb_id=None, tvdb_id=None):
    if not is_paid_user():
        return False
    
    headers = get_trakt_headers()
    if not headers:
        return False
    
    payload = {}
    
    if imdb_id:
        payload["movies"] = [{"ids": {"imdb": imdb_id}}]
    elif tvdb_id:
        payload["shows"] = [{"ids": {"tvdb": tvdb_id}}]
    else:
        return False
    
    url = "https://api.trakt.tv/sync/watchlist/remove"
    try:
        resp = requests.post(url, headers=headers, json=payload, timeout=15)
        if resp.status_code in (200, 201):
            log(f"Successfully removed item from watchlist", xbmc.LOGDEBUG)
            return True
        else:
            log(f"Failed to remove from watchlist: {resp.status_code} - {resp.text}", xbmc.LOGERROR)
            return False
    except Exception as e:
        log(f"Error removing from watchlist: {e}", xbmc.LOGERROR)
        return False

def trakt_mark_as_watched_simple(imdb_id=None, tvdb_id=None, season=None, episode=None):
    """Mark as watched for movies or TV episodes"""
    if not is_paid_user():
        return False
    
    headers = get_trakt_headers()
    if not headers:
        return False
    
    payload = {}
    
    if imdb_id:
        payload["movies"] = [{"ids": {"imdb": imdb_id}}]
    elif tvdb_id and season is not None and episode is not None:
        payload["episodes"] = [{"ids": {"tvdb": tvdb_id}, "season": season, "episode": episode}]
    elif tvdb_id:
        payload["shows"] = [{"ids": {"tvdb": tvdb_id}}]
    else:
        return False
    
    url = "https://api.trakt.tv/sync/history"
    try:
        resp = requests.post(url, headers=headers, json=payload, timeout=15)
        if resp.status_code in (200, 201):
            log(f"Successfully marked as watched: {payload}", xbmc.LOGDEBUG)
            return True
        else:
            log(f"Failed to mark as watched: {resp.status_code} - {resp.text}", xbmc.LOGERROR)
            return False
    except Exception as e:
        log(f"Error marking as watched: {e}", xbmc.LOGERROR)
        return False

def is_in_trakt_watchlist(imdb_id):
    if not is_paid_user():
        return False
    
    headers = get_trakt_headers()
    if not headers:
        return False
    
    try:
        url = "https://api.trakt.tv/sync/watchlist/movies"
        resp = requests.get(url, headers=headers, timeout=15)
        if resp.status_code == 200:
            watchlist = resp.json()
            for item in watchlist:
                if item.get('movie', {}).get('ids', {}).get('imdb') == imdb_id:
                    return True
    except Exception as e:
        log(f"Error checking watchlist: {e}", xbmc.LOGERROR)
    
    return False

def enhanced_episode_details(tv_id, season_num, episode_num, show_title=""):
    handle = int(sys.argv[1])
    tmdb = TMDBClient()

    episode = tmdb.get_episode_details(tv_id, season_num, episode_num)
    if not episode:
        return

    title = episode.get("name", f"Episode {episode_num}")
    label = f"{show_title} - S{season_num}E{episode_num}: {title}"

    play_url = get_url(
        action="play_tv",
        tv_id=tv_id,
        season=season_num,
        episode=episode_num,
        title=label
    )
    play_subs_url = get_url(
        action="play_tv_subs",
        tv_id=tv_id,
        season=season_num,
        episode=episode_num,
        title=label
    )

    item = xbmcgui.ListItem(label=label)
    still = build_image_url(episode.get("still_path"), "w500")
    fanart = build_image_url(episode.get("still_path"), BACKDROP_SIZE)
    item.setArt({
        'icon': still or 'DefaultVideo.png',
        'thumb': still or 'DefaultVideo.png',
        'fanart': fanart or ADDON_PATH + "/fanart.jpg"
    })
    item.setInfo('video', {
        'title': title,
        'plot': episode.get("overview", ""),
        'episode': episode_num,
        'season': season_num,
        'tvshowtitle': show_title
    })
    item.setProperty('IsPlayable', 'true')

    xbmcplugin.addDirectoryItem(handle, play_url, item, isFolder=False)

    play_subs_item = xbmcgui.ListItem(label=f"{label} with Subtitles")
    play_subs_item.setArt({'icon': 'DefaultVideo.png'})
    play_subs_item.setInfo('video', {'title': f"{label} with Subtitles"})
    play_subs_item.setProperty('IsPlayable', 'true')
    xbmcplugin.addDirectoryItem(handle, play_subs_url, play_subs_item, isFolder=False)

    xbmcplugin.setContent(handle, 'episodes')
    xbmcplugin.endOfDirectory(handle)

def play_tv_stream_with_subs(tv_id, season, episode, title):
    """Play TV stream WITH subtitle support - simplified"""
    log(f"Play TV stream with subs: tv_id={tv_id}, season={season}, episode={episode}", xbmc.LOGDEBUG)
    
    log_watch_history(f"tv/{tv_id}/{season}/{episode}", "tv_episode", title)
    
    stream_url = get_tv_stream(tv_id, season, episode)
    
    if not stream_url:
        xbmcgui.Dialog().notification(ADDON_NAME, "TV stream not available", xbmcgui.NOTIFICATION_ERROR)
        return
    
    subtitle_path = None
    
    try:
        tmdb_client = TMDBClient()
        tv_details = tmdb_client.get_tv_details(tv_id)
        if tv_details:
            imdb_id = tv_details.get("external_ids", {}).get("imdb_id")
            if imdb_id:
                log(f"Getting subtitles for TV show: {imdb_id}, season {season}, episode {episode}", xbmc.LOGDEBUG)
                subtitles = get_valid_subtitles(imdb_id, media_type="tv", season=season, episode=episode)
                
                if subtitles:
                    log(f"Found {len(subtitles)} subtitles, showing selector", xbmc.LOGDEBUG)
                    selected = show_subtitle_selector(subtitles)
                    
                    if selected and selected.get("url"):
                        subtitle_url = selected["url"]
                        sub_content = download_subtitle(subtitle_url)
                        
                        if sub_content and validate_subtitle_content(sub_content):
                            cache_dir = xbmcvfs.translatePath("special://profile/cache/")
                            if not xbmcvfs.exists(cache_dir):
                                xbmcvfs.mkdirs(cache_dir)
                            
                            import random
                            random_str = str(random.randint(1000, 9999))
                            sub_filename = f"sub_{imdb_id}_s{season}e{episode}_{int(time.time())}_{random_str}.srt"
                            subtitle_path = os.path.join(cache_dir, sub_filename)
                            
                            try:
                                with open(subtitle_path, 'w', encoding='utf-8-sig') as f:
                                    lines = sub_content.strip().split('\n')
                                    cleaned_lines = []
                                    for line in lines:
                                        line = line.strip()
                                        if line:
                                            line = line.replace('\ufeff', '').replace('\x00', '')
                                            cleaned_lines.append(line)
                                    cleaned_content = '\r\n'.join(cleaned_lines)
                                    f.write(cleaned_content)
                                
                                log(f"Subtitles saved to: {subtitle_path}")
                                
                                if os.path.exists(subtitle_path):
                                    file_size = os.path.getsize(subtitle_path)
                                    log(f"Subtitle file created, size: {file_size} bytes")
                                else:
                                    log(f"ERROR: Subtitle file not created at {subtitle_path}", xbmc.LOGERROR)
                                    subtitle_path = None
                                    
                            except Exception as e:
                                log(f"Failed to save subtitles: {str(e)}", xbmc.LOGERROR)
                                try:
                                    with open(subtitle_path, 'wb') as f:
                                        f.write(sub_content.encode('utf-8-sig'))
                                    log(f"Subtitles saved using binary mode")
                                except Exception as e2:
                                    log(f"Binary mode also failed: {str(e2)}", xbmc.LOGERROR)
                                    subtitle_path = None
                    else:
                        log("No subtitle selected or user cancelled", xbmc.LOGDEBUG)
                else:
                    log("No valid subtitles found", xbmc.LOGDEBUG)
    except Exception as e:
        log(f"Error getting subtitles for TV: {e}", xbmc.LOGDEBUG)
    
    if not stream_url.startswith("https://"):
        stream_url = f"https://{stream_url}"
    
    log(f"Playing TV: {stream_url[:100]}...")
    
    list_item = xbmcgui.ListItem(path=stream_url, label=title)
    list_item.setProperty('IsPlayable', 'true')
    list_item.setMimeType('application/vnd.apple.mpegurl')
    list_item.setContentLookup(False)
    
    list_item.setProperty('inputstream', 'inputstream.adaptive')
    list_item.setProperty('inputstream.adaptive.manifest_type', 'hls')
    list_item.setProperty('inputstream.adaptive.stream_headers', 
                         'User-Agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36')
    
    if subtitle_path and os.path.exists(subtitle_path):
        sub_path_for_kodi = subtitle_path.replace('\\', '/')
        
        list_item.setSubtitles([sub_path_for_kodi])
        list_item.setProperty('subtitle', sub_path_for_kodi)
        list_item.setProperty('subtitle.enable', 'true')
        
        log(f"Subtitles set from: {sub_path_for_kodi}")
    
    xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, list_item)

def enhanced_season_episodes(tv_id, season_num, show_title="", from_watchlist="false"):
    handle = int(sys.argv[1])
    tmdb = TMDBClient()

    season = tmdb.get_season_details(tv_id, season_num)

    if season and season.get("episodes"):
        for episode in season["episodes"]:
            ep_num = episode.get("episode_number", 1)
            title = episode.get("name", f"Episode {ep_num}")
            label = f"{ep_num}. {title}"
            
            episode_label = f"S{season_num}E{ep_num}: {title}"

            play_url = get_url(
                action="play_tv",
                tv_id=tv_id,
                season=season_num,
                episode=ep_num,
                title=f"{show_title} - {episode_label}",
                from_watchlist=from_watchlist
            )
            
            play_subs_url = get_url(
                action="play_tv_subs",
                tv_id=tv_id,
                season=season_num,
                episode=ep_num,
                title=f"{show_title} - {episode_label}",
                from_watchlist=from_watchlist
            )

            item = xbmcgui.ListItem(label=label)
            
            still = build_image_url(episode.get("still_path"), "w500")
            fanart = build_image_url(season.get("poster_path") or episode.get("still_path"), BACKDROP_SIZE)
            art = {
                'icon': still or 'DefaultVideo.png',
                'thumb': still or 'DefaultVideo.png',
                'fanart': fanart or ADDON_PATH + "/fanart.jpg"
            }
            item.setArt(art)

            info = {
                'title': title,
                'plot': episode.get("overview", ""),
                'episode': ep_num,
                'season': season_num,
                'tvshowtitle': show_title,
                'aired': episode.get("air_date", "")
            }
            item.setInfo('video', info)
            item.setProperty('IsPlayable', 'true')
            
            context_menu_items = [
                ("Play with Subtitles", f"PlayMedia({play_subs_url})")
            ]
            item.addContextMenuItems(context_menu_items)

            xbmcplugin.addDirectoryItem(handle, play_url, item, isFolder=False)

    xbmcplugin.setContent(handle, 'episodes')
    xbmcplugin.endOfDirectory(handle)

def enhanced_media_details(media_type, media_id):
    handle = int(sys.argv[1])
    tmdb = TMDBClient()
    
    params = dict(urllib.parse.parse_qsl(sys.argv[2][1:]))
    from_watchlist = params.get("from_watchlist", "false")

    if media_type == "movie":
        media = tmdb.get_movie_details(media_id)
        if not media:
            return

        title = media.get("title", "Unknown")
        imdb_id = media.get("imdb_id", "")

        if not imdb_id:
            xbmcgui.Dialog().notification(ADDON_NAME, "No IMDB ID found", xbmcgui.NOTIFICATION_ERROR)
            return

        can_use_trakt = is_paid_user()
        
        in_watchlist = False
        if can_use_trakt:
            headers = get_trakt_headers()
            if headers:
                in_watchlist = is_in_trakt_watchlist(imdb_id)

        play_url = get_url(action="play_movie", ttid=imdb_id, title=title)
        play_item = xbmcgui.ListItem(label=f"Play {title}")
        play_item.setProperty('IsPlayable', 'true')
        play_item.setArt({'icon': 'DefaultVideo.png'})
        play_item.setInfo('video', {'title': f"Play {title}"})
        xbmcplugin.addDirectoryItem(handle, play_url, play_item, isFolder=False)

        play_subs_url = get_url(action="play_movie_subs", ttid=imdb_id, title=title)
        play_subs_item = xbmcgui.ListItem(label=f"Play {title} with Subtitles")
        play_subs_item.setProperty('IsPlayable', 'true')
        play_subs_item.setArt({'icon': 'DefaultVideo.png'})
        play_subs_item.setInfo('video', {'title': f"Play {title} with Subtitles"})
        xbmcplugin.addDirectoryItem(handle, play_subs_url, play_subs_item, isFolder=False)

        if is_paid_user():
            similar_url = get_url(action="similar", media_type="movie", id=media_id)
            similar_item = xbmcgui.ListItem(label="Similar Movies")
            similar_item.setArt({'icon': 'DefaultFolder.png'})
            similar_item.setInfo('video', {'title': "Similar Movies"})
            xbmcplugin.addDirectoryItem(handle, similar_url, similar_item, isFolder=True)

            trailer = get_movie_trailers(media_id)
        
            if trailer and trailer.get("key"):
                trailer_url = get_url(action="play_trailer", youtube_id=trailer["key"], title=f"{title} Trailer")
                trailer_item = xbmcgui.ListItem(label=f"Play Trailer: {trailer['name']}")
                trailer_item.setProperty('IsPlayable', 'true')
                trailer_item.setArt({'icon': 'DefaultVideo.png'})
                trailer_item.setInfo('video', {'title': f"{title} Trailer"})
                xbmcplugin.addDirectoryItem(handle, trailer_url, trailer_item, isFolder=False)

        if can_use_trakt:
            headers = get_trakt_headers()
            if headers:
                if in_watchlist:
                    remove_url = get_url(action="trakt_remove_watchlist", imdb_id=imdb_id)
                    remove_item = xbmcgui.ListItem(label="Remove from Trakt Watchlist")
                    remove_item.setArt({'icon': 'DefaultVideo.png'})
                    remove_item.setInfo('video', {'title': "Remove from Trakt Watchlist"})
                    xbmcplugin.addDirectoryItem(handle, remove_url, remove_item, isFolder=False)
                else:
                    add_url = get_url(action="trakt_add_watchlist", imdb_id=imdb_id)
                    add_item = xbmcgui.ListItem(label="Add to Trakt Watchlist")
                    add_item.setArt({'icon': 'DefaultVideo.png'})
                    add_item.setInfo('video', {'title': "Add to Trakt Watchlist"})
                    xbmcplugin.addDirectoryItem(handle, add_url, add_item, isFolder=False)
            else:
                link_url = get_url(action="trakt_link")
                link_item = xbmcgui.ListItem(label="Link Trakt Account")
                link_item.setArt({'icon': 'DefaultVideo.png'})
                link_item.setInfo('video', {'title': "Link Trakt Account"})
                xbmcplugin.addDirectoryItem(handle, link_url, link_item, isFolder=True)

    elif media_type == "tv":
        media = tmdb.get_tv_details(media_id)
        if not media:
            return

        show_title = media.get("name", "TV Show")
        
        external_ids = media.get("external_ids", {})
        tvdb_id = external_ids.get("tvdb_id")
        
        can_use_trakt = is_paid_user()
        
        in_watchlist = False
        if can_use_trakt:
            headers = get_trakt_headers()
            if headers and tvdb_id:
                in_watchlist = is_tv_in_trakt_watchlist(tvdb_id)

        if is_paid_user():
            similar_url = get_url(action="similar", media_type="tv", id=media_id)
            similar_item = xbmcgui.ListItem(label="Similar TV Shows")
            similar_item.setArt({'icon': 'DefaultFolder.png'})
            similar_item.setInfo('video', {'title': "Similar TV Shows"})
            xbmcplugin.addDirectoryItem(handle, similar_url, similar_item, isFolder=True)

        if can_use_trakt:
            headers = get_trakt_headers()
            if headers and tvdb_id:
                if in_watchlist:
                    remove_url = get_url(action="trakt_remove_tv_watchlist", tvdb_id=tvdb_id)
                    remove_item = xbmcgui.ListItem(label="Remove from Trakt Watchlist")
                    remove_item.setArt({'icon': 'DefaultVideo.png'})
                    remove_item.setInfo('video', {'title': "Remove from Trakt Watchlist"})
                    xbmcplugin.addDirectoryItem(handle, remove_url, remove_item, isFolder=False)
                else:
                    add_url = get_url(action="trakt_add_tv_watchlist", tvdb_id=tvdb_id)
                    add_item = xbmcgui.ListItem(label="Add to Trakt Watchlist")
                    add_item.setArt({'icon': 'DefaultVideo.png'})
                    add_item.setInfo('video', {'title': "Add to Trakt Watchlist"})
                    xbmcplugin.addDirectoryItem(handle, add_url, add_item, isFolder=False)
            elif not headers:
                link_url = get_url(action="trakt_link")
                link_item = xbmcgui.ListItem(label="Link Trakt Account")
                link_item.setArt({'icon': 'DefaultVideo.png'})
                link_item.setInfo('video', {'title': "Link Trakt Account"})
                xbmcplugin.addDirectoryItem(handle, link_url, link_item, isFolder=True)

        if media.get("seasons"):
            for season in media["seasons"]:
                season_num = season.get("season_number", 0)
                if season_num == 0:
                    continue

                season_name = season.get("name", f"Season {season_num}")
                label = season_name
                
                episode_count = season.get("episode_count", 0)
                if episode_count > 0:
                    label = f"{label} ({episode_count} episodes)"
                
                url = get_url(action="season_episodes", id=media_id, season=season_num, show_title=show_title, from_watchlist=from_watchlist)
                item = xbmcgui.ListItem(label=label)

                poster = build_image_url(season.get("poster_path"), POSTER_SIZE)
                fanart = build_image_url(media.get("backdrop_path"), BACKDROP_SIZE)
                
                item.setArt({
                    'icon': poster or 'DefaultFolder.png', 
                    'thumb': poster or 'DefaultFolder.png', 
                    'fanart': fanart or ADDON_PATH + "/fanart.jpg"
                })
                
                item.setInfo('video', {
                    'title': season_name,
                    'tvshowtitle': show_title,
                    'plot': season.get("overview", media.get("overview", "")),
                    'season': season_num
                })
                
                xbmcplugin.addDirectoryItem(handle, url, item, isFolder=True)

    xbmcplugin.setContent(handle, 'movies' if media_type=="movie" else 'tvshows')
    xbmcplugin.endOfDirectory(handle)

def get_client_id():
    if xbmcvfs.exists(CLIENT_ID_FILE):
        try:
            with xbmcvfs.File(CLIENT_ID_FILE, 'r') as f:
                client_id = f.read().strip()
                if client_id:
                    return client_id
        except Exception as e:
            log(f"Error reading client ID: {e}", xbmc.LOGDEBUG)
    
    client_id = str(uuid.uuid4())
    
    try:
        folder = xbmcvfs.translatePath(f"special://profile/addon_data/{ADDON_ID}")
        if not xbmcvfs.exists(folder):
            xbmcvfs.mkdirs(folder)
            log(f"Created folder: {folder}", xbmc.LOGDEBUG)
        
        with xbmcvfs.File(CLIENT_ID_FILE, 'w') as f:
            f.write(client_id)
        log(f"Generated new client ID: {client_id}", xbmc.LOGDEBUG)
        
    except Exception as e:
        log(f"Failed to save client ID: {str(e)}", xbmc.LOGERROR)
        return "fallback-" + str(uuid.uuid4())[:8]
    
    return client_id

def log(msg, level=xbmc.LOGINFO):
    xbmc.log(f"[{ADDON_ID}] {msg}", level)

def get_url(**kwargs):
    return f"plugin://{ADDON_ID}?{urllib.parse.urlencode(kwargs)}"

def make_request(url, params=None, timeout=10):
    try:
        headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
            'Accept': 'application/json'
        }
        response = requests.get(url, params=params, headers=headers, timeout=timeout)
        response.raise_for_status()
        return response.json()
    except Exception as e:
        log(f"Request failed: {url} - Error: {str(e)}", xbmc.LOGERROR)
        return None

def get_movie_trailers(tmdb_id):
    """Get movie trailers from TMDB"""
    try:
        url = f"{TMDB_BASE_URL}/movie/{tmdb_id}/videos"
        params = {"api_key": TMDB_API_KEY}
        
        response = requests.get(url, params=params, timeout=10)
        if response.status_code == 200:
            data = response.json()
            trailers = []
            
            for video in data.get("results", []):
                if video.get("type") == "Trailer" and video.get("site") == "YouTube":
                    trailers.append({
                        "name": video.get("name", "Trailer"),
                        "key": video.get("key"),
                        "type": video.get("type"),
                        "site": video.get("site")
                    })
            
            return trailers[0] if trailers else None
    except Exception as e:
        log(f"Error getting trailers: {e}", xbmc.LOGDEBUG)
    
    return None

def play_youtube_trailer(youtube_id, title):
    """Play YouTube trailer"""
    log(f"Playing YouTube trailer: {youtube_id}", xbmc.LOGDEBUG)
    
    youtube_url = f"plugin://plugin.video.youtube/play/?video_id={youtube_id}"
    
    list_item = xbmcgui.ListItem(path=youtube_url, label=title)
    list_item.setProperty('IsPlayable', 'true')
    
    list_item.setProperty('isplaying', 'true')
    list_item.setContentLookup(False)
    
    xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, list_item)

class SubtitlePlayer(xbmc.Player):
    def __init__(self, subtitle_path=None, subtitle_offset=0.0):
        super().__init__()
        self.subtitle_path = subtitle_path
        self.subtitle_offset = subtitle_offset

    def onAVStarted(self):
        xbmc.sleep(500)

        if self.subtitle_path and xbmcvfs.exists(self.subtitle_path):
            kodi_path = self.subtitle_path.replace("\\", "/")
            self.setSubtitles(kodi_path)

        try:
            xbmc.executeJSONRPC(json.dumps({
                "jsonrpc": "2.0",
                "method": "Player.SetSubtitleOffset",
                "params": {
                    "playerid": 1,
                    "offset": self.subtitle_offset
                },
                "id": 1
            }))
        except Exception as e:
            xbmc.log(f"[{ADDON_NAME}] Subtitle offset error: {e}", xbmc.LOGERROR)


class TMDBClient:
    
    def __init__(self):
        self.api_key = TMDB_API_KEY
        self.base_params = {"api_key": self.api_key, "language": "en-US"}
    
    def get_movie_genres(self):
        url = f"{TMDB_BASE_URL}/genre/movie/list"
        data = make_request(url, self.base_params)
        return data.get("genres", []) if data else []
    
    def get_tv_genres(self):
        url = f"{TMDB_BASE_URL}/genre/tv/list"
        data = make_request(url, self.base_params)
        return data.get("genres", []) if data else []
    
    def get_popular_movies(self, page=1):
        url = f"{TMDB_BASE_URL}/movie/popular"
        params = {**self.base_params, "page": page}
        return make_request(url, params)
    
    def get_top_rated_movies(self, page=1):
        url = f"{TMDB_BASE_URL}/movie/top_rated"
        params = {**self.base_params, "page": page}
        return make_request(url, params)
    
    def get_now_playing_movies(self, page=1):
        url = f"{TMDB_BASE_URL}/movie/now_playing"
        params = {**self.base_params, "page": page}
        return make_request(url, params)
    
    def get_upcoming_movies(self, page=1):
        url = f"{TMDB_BASE_URL}/movie/upcoming"
        params = {**self.base_params, "page": page}
        return make_request(url, params)
    
    def get_popular_tv(self, page=1):
        url = f"{TMDB_BASE_URL}/tv/popular"
        params = {**self.base_params, "page": page}
        return make_request(url, params)
    
    def get_top_rated_tv(self, page=1):
        url = f"{TMDB_BASE_URL}/tv/top_rated"
        params = {**self.base_params, "page": page}
        return make_request(url, params)
    
    def get_tv_on_air(self, page=1):
        url = f"{TMDB_BASE_URL}/tv/on_the_air"
        params = {**self.base_params, "page": page}
        return make_request(url, params)
    
    def get_movies_by_genre(self, genre_id, page=1):
        url = f"{TMDB_BASE_URL}/discover/movie"
        params = {
            **self.base_params,
            "with_genres": genre_id,
            "sort_by": "popularity.desc",
            "page": page
        }
        return make_request(url, params)
    
    def get_tv_by_genre(self, genre_id, page=1):
        url = f"{TMDB_BASE_URL}/discover/tv"
        params = {
            **self.base_params,
            "with_genres": genre_id,
            "sort_by": "popularity.desc",
            "page": page
        }
        return make_request(url, params)
    
    def search_movies(self, query, page=1):
        url = f"{TMDB_BASE_URL}/search/movie"
        params = {**self.base_params, "query": query, "page": page}
        return make_request(url, params)
    
    def search_tv(self, query, page=1):
        url = f"{TMDB_BASE_URL}/search/tv"
        params = {**self.base_params, "query": query, "page": page}
        return make_request(url, params)
    
    def get_movie_details(self, movie_id):
        url = f"{TMDB_BASE_URL}/movie/{movie_id}"
        params = {**self.base_params, "append_to_response": "credits,external_ids"}
        return make_request(url, params)
    
    def get_tv_details(self, tv_id):
        url = f"{TMDB_BASE_URL}/tv/{tv_id}"
        params = {**self.base_params, "append_to_response": "credits,seasons,external_ids"}
        return make_request(url, params)
    
    def get_season_details(self, tv_id, season_number):
        url = f"{TMDB_BASE_URL}/tv/{tv_id}/season/{season_number}"
        return make_request(url, self.base_params)
    
    def get_episode_details(self, tv_id, season_number, episode_number):
        url = f"{TMDB_BASE_URL}/tv/{tv_id}/season/{season_number}/episode/{episode_number}"
        params = {**self.base_params, "append_to_response": "external_ids"}
        return make_request(url, params)
    
    def get_trending_movies(self, page=1):
        url = f"{TMDB_BASE_URL}/trending/movie/week"
        params = {**self.base_params, "page": page}
        return make_request(url, params)

    def get_trending_tv(self, page=1):
        url = f"{TMDB_BASE_URL}/trending/tv/week"
        params = {**self.base_params, "page": page}
        return make_request(url, params)

    def get_tv_airing_today(self, page=1):
        url = f"{TMDB_BASE_URL}/tv/airing_today"
        params = {**self.base_params, "page": page}
        return make_request(url, params)
    
    def get_movie_recommendations(self, movie_id, page=1):
        url = f"{TMDB_BASE_URL}/movie/{movie_id}/recommendations"
        params = {**self.base_params, "page": page}
        return make_request(url, params)
    
    def get_movie_similar(self, movie_id, page=1):
        url = f"{TMDB_BASE_URL}/movie/{movie_id}/similar"
        params = {**self.base_params, "page": page}
        return make_request(url, params)
    
    def get_tv_recommendations(self, tv_id, page=1):
        url = f"{TMDB_BASE_URL}/tv/{tv_id}/recommendations"
        params = {**self.base_params, "page": page}
        return make_request(url, params)
    
    def get_tv_similar(self, tv_id, page=1):
        url = f"{TMDB_BASE_URL}/tv/{tv_id}/similar"
        params = {**self.base_params, "page": page}
        return make_request(url, params)
    
    def search_person(self, query, page=1):
        """Search for a person (actor/director)"""
        url = f"{TMDB_BASE_URL}/search/person"
        params = {**self.base_params, "query": query, "page": page}
        return make_request(url, params)
    
    def get_person_details(self, person_id):
        """Get detailed information about a person including their filmography"""
        url = f"{TMDB_BASE_URL}/person/{person_id}"
        params = {**self.base_params, "append_to_response": "combined_credits"}
        return make_request(url, params)

def get_stream_url(ttid, retry=True):
    user_api_key = ADDON.getSetting("paid_api_key")
    if user_api_key:
        user_api_key = user_api_key.strip()
    
    api_key = "FREE-ABC-123" 
    is_paid_cached = False
    
    if user_api_key and xbmcvfs.exists(PAID_CACHE_FILE):
        try:
            with xbmcvfs.File(PAID_CACHE_FILE, 'r') as f:
                cache_data = json.load(f)
                
            cache_age = time.time() - cache_data.get("timestamp", 0)
            key_matches = cache_data.get("api_key") == user_api_key
            
            if cache_age < 3600 and key_matches:  # 60 minute cache
                is_paid_cached = cache_data.get("is_paid", False)
                if is_paid_cached:
                    api_key = user_api_key
                    log(f"Using cached paid validation (age: {cache_age:.1f}s)", xbmc.LOGDEBUG)
                else:
                    log(f"Using cached free validation (age: {cache_age:.1f}s)", xbmc.LOGDEBUG)
            else:
                log(f"Cache expired or key mismatch (age: {cache_age:.1f}s)", xbmc.LOGDEBUG)
                is_paid_cached = is_paid_user()
                api_key = user_api_key if is_paid_cached else "FREE-ABC-123"
        except Exception as e:
            log(f"Error reading cache: {e}", xbmc.LOGDEBUG)
            is_paid_cached = is_paid_user()
            api_key = user_api_key if is_paid_cached else "FREE-ABC-123"
    elif user_api_key:
        is_paid_cached = is_paid_user()
        api_key = user_api_key if is_paid_cached else "FREE-ABC-123"
    else:
        log(f"No API key provided, using free key", xbmc.LOGDEBUG)
    
    client_id = get_client_id()
    
    headers = {
        "X-API-Key": api_key,
        "X-Client-ID": client_id,
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
        "Accept": "application/json"
    }

    try:
        log(f"Client ID: {client_id}", xbmc.LOGDEBUG)
        log(f"Requesting stream for: {ttid}", xbmc.LOGDEBUG)
        
        response = requests.get(
            STREAM_API_URL,
            headers=headers,
            params={"d": ttid},
            timeout=30
        )

        log(f"Stream API response ({response.status_code}): {response.text[:500]}...", xbmc.LOGDEBUG)

        if response.status_code == 200:
            data = response.json()
            stream_url = data.get("data", {}).get("stream_info", {}).get("url")
            if stream_url:
                log(f"Got stream URL: {stream_url[:100]}...", xbmc.LOGDEBUG)
                
                if response.status_code == 401 and user_api_key and user_api_key != "FREE-ABC-123":
                    is_paid_user(force_refresh=True)
                    
                return stream_url
            else:
                log(f"No stream URL found in response", xbmc.LOGWARNING)
                return None
        
        if response.status_code == 429:
            detail = "Rate limited"
            try:
                detail = response.json().get("detail", detail)
            except:
                pass
            retry_after = response.headers.get("Retry-After")
            if retry_after:
                detail += f" - try again in {retry_after} seconds"
            xbmcgui.Dialog().notification(ADDON_NAME, detail, xbmcgui.NOTIFICATION_ERROR)
            return None
            
        elif response.status_code in (401, 400):
            error_msg = "API key or client ID rejected"
            try:
                error_data = response.json()
                error_msg = error_data.get("detail", error_msg)
            except:
                pass
            
            if user_api_key and user_api_key != "FREE-ABC-123":
                log(f"User API key rejected: {error_msg}", xbmc.LOGERROR)
                if xbmcvfs.exists(PAID_CACHE_FILE):
                    xbmcvfs.delete(PAID_CACHE_FILE)
                    log("Cleared paid cache due to invalid API key", xbmc.LOGDEBUG)
            
            xbmcgui.Dialog().notification(ADDON_NAME, error_msg, xbmcgui.NOTIFICATION_ERROR)
            return None
            
        else:
            log(f"Unexpected API status {response.status_code}: {response.text[:200]}", xbmc.LOGERROR)
            xbmcgui.Dialog().notification(ADDON_NAME, f"API error: {response.status_code}", xbmcgui.NOTIFICATION_ERROR)
            return None

    except requests.exceptions.Timeout:
        log("Stream API timeout", xbmc.LOGERROR)
        xbmcgui.Dialog().notification(ADDON_NAME, "Connection timeout", xbmcgui.NOTIFICATION_ERROR)
        return None
        
    except Exception as e:
        log(f"Stream API error: {e}", xbmc.LOGERROR)
        xbmcgui.Dialog().notification(ADDON_NAME, "Stream error", xbmc.LOGERROR)
        return None

def get_tmdb_ids_from_history():
    """Extract TMDB IDs from watch history"""
    history = get_watch_history()
    tmdb_ids = set()
    
    log(f"Watch history has {len(history['movies'])} movies and {len(history['tv_episodes'])} TV episodes", xbmc.LOGDEBUG)
    
    for movie in history["movies"]:
        imdb_id = movie.get("id", "")
        
        if imdb_id and imdb_id.startswith("tt"):
            try:
                tmdb_id = convert_imdb_to_tmdb(imdb_id)
                if tmdb_id:
                    tmdb_ids.add(str(tmdb_id))
                    log(f"Converted IMDB {imdb_id} to TMDB {tmdb_id}", xbmc.LOGDEBUG)
                else:
                    log(f"Could not convert IMDB {imdb_id} to TMDB", xbmc.LOGDEBUG)
            except Exception as e:
                log(f"Error converting IMDB ID {imdb_id}: {e}", xbmc.LOGDEBUG)
    
    for tv_episode in history["tv_episodes"]:
        ep_id = tv_episode.get("id", "")
        if ep_id and "tv/" in ep_id:
            parts = ep_id.split("/")
            if len(parts) >= 2:
                tv_id = parts[1]
                tmdb_ids.add(str(tv_id))
                log(f"Added TV show ID: {tv_id}", xbmc.LOGDEBUG)
    
    log(f"Extracted {len(tmdb_ids)} TMDB IDs: {list(tmdb_ids)[:10]}...", xbmc.LOGDEBUG)
    return list(tmdb_ids)

def convert_imdb_to_tmdb(imdb_id):
    """Convert IMDB ID to TMDB ID"""
    try:
        url = f"{TMDB_BASE_URL}/find/{imdb_id}"
        params = {
            "api_key": TMDB_API_KEY,
            "external_source": "imdb_id"
        }
        
        response = requests.get(url, params=params, timeout=10)
        if response.status_code == 200:
            data = response.json()
            # Check for movie results
            if data.get("movie_results") and len(data["movie_results"]) > 0:
                tmdb_id = data["movie_results"][0]["id"]
                log(f"Converted IMDB {imdb_id} to TMDB {tmdb_id}", xbmc.LOGDEBUG)
                return tmdb_id
    except Exception as e:
        log(f"Error converting IMDB ID {imdb_id} to TMDB: {e}", xbmc.LOGDEBUG)
    
    return None

def convert_tmdb_to_imdb(tmdb_id):
    """Convert TMDB ID to IMDB ID"""
    try:
        url = f"{TMDB_BASE_URL}/movie/{tmdb_id}"
        params = {
            "api_key": TMDB_API_KEY,
            "language": "en-US"
        }
        
        response = requests.get(url, params=params, timeout=10)
        if response.status_code == 200:
            data = response.json()
            imdb_id = data.get("imdb_id")
            if imdb_id:
                log(f"Converted TMDB {tmdb_id} to IMDB {imdb_id}", xbmc.LOGDEBUG)
                return imdb_id
    except Exception as e:
        log(f"Error converting TMDB ID {tmdb_id} to IMDB: {e}", xbmc.LOGDEBUG)
    
    return None

def get_tv_stream(tv_id, season, episode):
    try:
        tv_format = f"tv/{tv_id}/{season}/{episode}"
        log(f"Getting TV stream for: {tv_format}", xbmc.LOGDEBUG)
        return get_stream_url(tv_format)
    except Exception as e:
        log(f"TV Stream API error: {str(e)}", xbmc.LOGERROR)
    return None

def search_actor_menu():
    """Show actor search menu from main search"""
    keyboard = xbmc.Keyboard()
    keyboard.setHeading("Search for Actor/Director")
    keyboard.doModal()
    
    if keyboard.isConfirmed():
        query = keyboard.getText()
        if query:
            perform_actor_search(query)

def perform_actor_search(query, page=1):
    """Search for actors and display results"""
    handle = int(sys.argv[1])
    tmdb = TMDBClient()
    
    log(f"Searching for actor: {query}", xbmc.LOGDEBUG)
    
    data = tmdb.search_person(query, page)
    
    if data and data.get("results"):
        for person in data["results"]:
            name = person.get("name", "Unknown")
            known_for = person.get("known_for_department", "Acting")
            popularity = person.get("popularity", 0)
            
            known_for_titles = []
            if person.get("known_for"):
                for work in person["known_for"]:
                    title = work.get("title") or work.get("name") or "Unknown"
                    known_for_titles.append(title)
                    if len(known_for_titles) >= 3:
                        break
            
            label = name
            
            url = get_url(action="actor_details", id=person["id"])
            list_item = xbmcgui.ListItem(label=label)
            
            profile_path = person.get("profile_path")
            poster = build_image_url(profile_path, "w185") if profile_path else "DefaultActor.png"
            fanart = ADDON_PATH + "/fanart.jpg"
            
            art = {
                'icon': poster,
                'thumb': poster,
                'poster': poster,
                'fanart': fanart
            }
            list_item.setArt(art)
            
            info_text = ""
            if known_for:
                info_text += f"Known for: {known_for}\n"
            if known_for_titles:
                info_text += f"Notable works: {', '.join(known_for_titles)}\n"
            if person.get("gender") == 1:
                info_text += "Gender: Female\n"
            elif person.get("gender") == 2:
                info_text += "Gender: Male\n"
            if person.get("birthday"):
                info_text += f"Birthday: {person['birthday']}\n"
            if person.get("place_of_birth"):
                info_text += f"Place of birth: {person['place_of_birth']}\n"
            if popularity > 0:
                info_text += f"Popularity score: {popularity:.1f}"
            
            info_text = info_text.strip()
            
            log(f"Actor {name} info text: {info_text[:100]}...", xbmc.LOGDEBUG)
            
            info = {
                'title': name,
                'plot': info_text,
                'plotoutline': info_text[:100] if info_text else "",  
                'mediatype': 'artist'
            }
            
            list_item.setInfo(type='video', infoLabels=info)
            
            if info_text:
                list_item.setProperty('plot', info_text)
                list_item.setProperty('plotoutline', info_text[:100])
            
            list_item.setProperty('IsPlayable', 'false')
            list_item.setProperty('IsFolder', 'true')
            
            xbmcplugin.addDirectoryItem(handle, url, list_item, isFolder=True)
        
        total_pages = data.get("total_pages", 1)
        if total_pages > page:
            next_url = get_url(action="actor_search", query=query, page=page + 1)
            next_item = xbmcgui.ListItem(label=f"Next Page ({page + 1}/{total_pages})")
            next_item.setArt({'icon': 'DefaultFolder.png'})
            next_item.setInfo('video', {'title': "Next Page"})
            xbmcplugin.addDirectoryItem(handle, next_url, next_item, isFolder=True)
    else:
        list_item = xbmcgui.ListItem(label="No actors found")
        list_item.setArt({'icon': 'DefaultFolder.png'})
        list_item.setInfo('video', {'title': "No results"})
        xbmcplugin.addDirectoryItem(handle, "", list_item, isFolder=False)
    
    xbmcplugin.setContent(handle, 'artists')
    xbmcplugin.endOfDirectory(handle)

def show_actor_details(person_id):
    """Show actor filmography sorted by rating but filter out low-viewership items"""
    handle = int(sys.argv[1])
    tmdb = TMDBClient()
    
    person = tmdb.get_person_details(person_id)
    
    if not person:
        xbmcgui.Dialog().notification(ADDON_NAME, "Actor information not available", xbmcgui.NOTIFICATION_ERROR)
        xbmcplugin.endOfDirectory(handle)
        return
    
    name = person.get("name", "Unknown")
    
    combined_credits = person.get("combined_credits", {})
    cast_items = combined_credits.get("cast", [])
    
    all_credits = []
    
    for credit in cast_items:
        media_type = credit.get("media_type")
        vote_average = credit.get("vote_average", 0)
        vote_count = credit.get("vote_count", 0)
        popularity = credit.get("popularity", 0)
        
        if media_type == "movie":
            all_credits.append({
                'id': credit.get("id"),
                'title': credit.get("title"),
                'character': credit.get("character"),
                'year': credit.get("release_date", "")[:4] if credit.get("release_date") else "",
                'poster_path': credit.get("poster_path"),
                'vote_average': vote_average,
                'vote_count': vote_count,
                'popularity': popularity,
                'overview': credit.get("overview", ""),
                'type': 'movie'
            })
        elif media_type == "tv":
            all_credits.append({
                'id': credit.get("id"),
                'title': credit.get("name"),
                'character': credit.get("character"),
                'year': credit.get("first_air_date", "")[:4] if credit.get("first_air_date") else "",
                'poster_path': credit.get("poster_path"),
                'vote_average': vote_average,
                'vote_count': vote_count,
                'popularity': popularity,
                'overview': credit.get("overview", ""),
                'type': 'tv'
            })
    
    filtered_credits = []
    for credit in all_credits:
        vote_count = credit.get('vote_count', 0)
        popularity = credit.get('popularity', 0)
        vote_average = credit.get('vote_average', 0)
        
        has_poster = bool(credit.get('poster_path'))
        has_year = bool(credit.get('year'))
        is_major_work = has_poster and has_year
        
        if (vote_count > 50) or (popularity > 5) or is_major_work:
            filtered_credits.append(credit)
    
    display_credits = filtered_credits if len(filtered_credits) >= 5 else all_credits
    
    for credit in display_credits:
        vote_average = credit.get('vote_average', 0)
        vote_count = credit.get('vote_count', 0)
        
        import math
        weight = math.log(vote_count + 1) / math.log(1000)  # Normalize to 0-1 scale
        weighted_score = vote_average * (0.7 + 0.3 * weight)  # 70% rating, 30% vote weight
        
        credit['weighted_score'] = weighted_score
    
    display_credits.sort(key=lambda x: x.get('weighted_score', 0), reverse=True)
    
    for credit in display_credits:
        title = credit.get('title', 'Unknown')
        character = credit.get('character', '')
        year = credit.get('year', '')
        rating = credit.get('vote_average', 0)
        vote_count = credit.get('vote_count', 0)
        overview = credit.get('overview', '')
        
        label = f"{title}"
        if year:
            label += f" ({year})"
        if rating > 0 and vote_count > 10:
            label += f" ★ {rating:.1f}"
        
        if credit['type'] == 'movie':
            url = get_url(action="movie_details", id=credit["id"])
            media_info = {'mediatype': 'movie'}
        else:
            url = get_url(action="tv_details", id=credit["id"])
            media_info = {'mediatype': 'tvshow'}
        
        list_item = xbmcgui.ListItem(label=label)
        
        poster = build_image_url(credit.get("poster_path"), POSTER_SIZE)
        fanart = ADDON_PATH + "/fanart.jpg"
        
        art = {
            'icon': poster,
            'thumb': poster,
            'poster': poster,
            'fanart': fanart
        }
        list_item.setArt(art)
        
        plot_text = ""
        if character:
            plot_text += f"Role: {character}\n\n"
        if overview:
            plot_text += f"{overview}"
        
        info = {
            'title': title,
            'year': int(year) if year and year.isdigit() else 0,
            'plot': plot_text,
            'rating': float(rating) if rating > 0 else 0
        }
        info.update(media_info)
        list_item.setInfo('video', info)
        
        xbmcplugin.addDirectoryItem(handle, url, list_item, isFolder=True)
    
    xbmcplugin.setContent(handle, 'videos')
    xbmcplugin.endOfDirectory(handle)

def download_subtitle(subtitle_url):
    """Download subtitle - very simple"""
    log(f"Downloading subtitle from: {subtitle_url}", xbmc.LOGDEBUG)
    
    try:
        response = requests.get(subtitle_url, timeout=10)
        
        if response.status_code == 200:
            content = response.content
            log(f"Downloaded {len(content)} bytes", xbmc.LOGDEBUG)
            
            encodings = ['utf-8-sig', 'utf-8', 'latin-1', 'cp1252']
            
            for encoding in encodings:
                try:
                    decoded = content.decode(encoding)
                    log(f"Successfully decoded with {encoding}", xbmc.LOGDEBUG)
                    return decoded
                except UnicodeDecodeError:
                    continue
            
            return content.decode('utf-8', errors='ignore')
    
    except Exception as e:
        log(f"Download error: {str(e)}", xbmc.LOGDEBUG)
    
    return ""

def show_subtitle_selector(subtitles_data):
    """Show simple subtitle selector"""
    if not subtitles_data:
        log("No subtitles to show", xbmc.LOGDEBUG)
        return None
    
    items = []
    
    for sub in subtitles_data:
        language = sub.get("display", sub.get("language", "Unknown"))
        format_type = sub.get("format", "srt").upper()
        source = sub.get("source", "")
        
        label = f"{language} ({format_type})"
        if source:
            label += f" - {source}"
        
        items.append(label)
    
    items.append("No subtitles")
    
    dialog = xbmcgui.Dialog()
    choice = dialog.select("Select Subtitles", items)
    
    if choice >= 0 and choice < len(subtitles_data):
        log(f"User selected subtitle {choice}", xbmc.LOGDEBUG)
        return subtitles_data[choice]
    
    log("User selected 'No subtitles' or cancelled", xbmc.LOGDEBUG)
    return None

def get_max_resolution_setting():
    """
    Returns a value suitable for inputstream.adaptive.max_resolution
    """
    value = ADDON.getSetting("max_resolution")

    mapping = {
        "0": "0",     
        "1": "2160",  
        "2": "1080",
        "3": "720",
        "4": "480",
    }

    return mapping.get(value, "0")

def play_stream(ttid, title, from_watchlist="false"):
    """Play stream WITHOUT subtitles (optimized for quality & buffering)"""
    log(f"Play stream called with ttid={ttid}, title={title}", xbmc.LOGDEBUG)

    log_watch_history(ttid, "movie", title)

    if is_paid_user():
        headers = get_trakt_headers()
        if headers and is_in_trakt_watchlist(ttid):
            trakt_remove_from_watchlist_simple(imdb_id=ttid)
            trakt_mark_as_watched_simple(imdb_id=ttid)

    stream_url = get_stream_url(ttid)
    if not stream_url:
        xbmcgui.Dialog().notification(
            ADDON_NAME, "Stream not available", xbmcgui.NOTIFICATION_ERROR
        )
        return

    if not stream_url.startswith("https://"):
        stream_url = f"https://{stream_url}"

    max_res = get_max_resolution_setting()

    list_item = xbmcgui.ListItem(path=stream_url, label=title)
    list_item.setProperty("IsPlayable", "true")
    list_item.setProperty("IsInternetStream", "true")
    list_item.setMimeType("application/vnd.apple.mpegurl")
    list_item.setContentLookup(False)
    list_item.setProperty("inputstream", "inputstream.adaptive")
    list_item.setProperty("inputstream.adaptive.manifest_type", "hls")
    list_item.setProperty(
        "inputstream.adaptive.max_resolution", max_res
    )
    list_item.setProperty(
        "inputstream.adaptive.play_timeshift_buffer", "true"
    )
    list_item.setProperty(
        "inputstream.adaptive.manifest_update_parameter", "full"
    )

    list_item.setProperty(
        "inputstream.adaptive.stream_headers",
        "User-Agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64)"
    )
    list_item.setProperty("inputstream.adaptive.max_buffer_size", "104857600")
    list_item.setInfo("video", {
        "title": title,
        "mediatype": "movie"
    })

    xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, list_item)

def play_tv_stream(tv_id, season, episode, title, from_watchlist="false"):
    """Play a single TV episode with auto-next support for paid users."""
    log_watch_history(f"tv/{tv_id}/{season}/{episode}", "tv_episode", title)

    stream_url = get_tv_stream(tv_id, season, episode)
    if not stream_url:
        xbmcgui.Dialog().notification(ADDON_NAME, "TV stream not available", xbmcgui.NOTIFICATION_ERROR)
        return

    if not stream_url.startswith("https://"):
        stream_url = f"https://{stream_url}"

    max_res = get_max_resolution_setting()
    xbmc.log(f"[{ADDON_NAME}] Playing S{season}E{episode} at max resolution {max_res}", xbmc.LOGDEBUG)

    list_item = xbmcgui.ListItem(path=stream_url, label=title)
    list_item.setProperty("IsPlayable", "true")
    list_item.setProperty("inputstream", "inputstream.adaptive")
    list_item.setProperty("inputstream.adaptive.max_resolution", max_res)
    list_item.setProperty("inputstream.adaptive.play_timeshift_buffer", "true")

    xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, list_item)

def play_stream_with_subs(ttid, title, from_watchlist="false"):
    """Play stream WITH subtitles, using base delay and optimized for resolution & buffering"""
    log(f"=== START play_stream_with_subs: {ttid} ===", xbmc.LOGDEBUG)

    log_watch_history(ttid, "movie", title)

    if is_paid_user():
        headers = get_trakt_headers()
        if headers and is_in_trakt_watchlist(ttid):
            trakt_remove_from_watchlist_simple(imdb_id=ttid)
            trakt_mark_as_watched_simple(imdb_id=ttid)

    stream_url = get_stream_url(ttid)
    if not stream_url:
        xbmcgui.Dialog().notification(
            ADDON_NAME, "Stream not available", xbmcgui.NOTIFICATION_ERROR
        )
        return

    subtitle_path = None

    subtitles = get_valid_subtitles(ttid, media_type="movie")
    if subtitles:
        selected = show_subtitle_selector(subtitles)
        if selected and selected.get("url"):
            sub_content = download_subtitle(selected["url"])
            if sub_content:
                try:
                    base_delay = float(ADDON.getSetting("base_stream_delay"))
                except:
                    base_delay = 1.5 
                temp_dir = xbmcvfs.translatePath("special://temp/")
                sub_filename = f"sub_{ttid}_{int(time.time())}.srt"
                subtitle_path = os.path.join(temp_dir, sub_filename)

                try:
                    with open(subtitle_path, "w", encoding="utf-8-sig") as f:
                        f.write(sub_content)
                except Exception as e:
                    log(f"Subtitle save error: {e}", xbmc.LOGERROR)
                    subtitle_path = None

    if not stream_url.startswith("https://"):
        stream_url = f"https://{stream_url}"

    max_res = get_max_resolution_setting()  

    list_item = xbmcgui.ListItem(path=stream_url, label=title)
    list_item.setProperty("IsPlayable", "true")
    list_item.setProperty("IsInternetStream", "true")
    list_item.setMimeType("application/vnd.apple.mpegurl")
    list_item.setContentLookup(False)

    list_item.setProperty("inputstream", "inputstream.adaptive")
    list_item.setProperty("inputstream.adaptive.manifest_type", "hls")
    list_item.setProperty(
        "inputstream.adaptive.stream_headers",
        "User-Agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64)"
    )

    list_item.setProperty("inputstream.adaptive.max_resolution", max_res)
    list_item.setProperty("inputstream.adaptive.play_timeshift_buffer", "true")
    list_item.setProperty("inputstream.adaptive.manifest_update_parameter", "full")
    list_item.setProperty("inputstream.adaptive.max_buffer_size", "104857600")

    if subtitle_path and xbmcvfs.exists(subtitle_path):
        kodi_path = subtitle_path.replace("\\", "/")
        list_item.setSubtitles([kodi_path])

    list_item.setInfo("video", {
        "title": title,
        "mediatype": "movie"
    })

    xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, list_item)
    log(f"Applied base subtitle delay: {base_delay}s", xbmc.LOGDEBUG)
    log("=== END play_stream_with_subs ===", xbmc.LOGDEBUG)

def build_image_url(path, size="w500"):
    if not path:
        return ""
    return f"{IMAGE_BASE_URL}{size}{path}"

def link_trakt_account():
    if not is_paid_user():
        xbmcgui.Dialog().notification(ADDON_NAME, "Paid feature only", xbmcgui.NOTIFICATION_ERROR)
        return
    show_trakt_url_simple()

def show_trakt_url_simple():
    trakt_url = "https://shorturl.at/hfp6R"
    
    xbmcgui.Dialog().textviewer(
        "Link Trakt Account",
        f"OPEN THIS LINK ON YOUR PHONE:\n\n"
        f"{trakt_url}\n\n"
        "EASY STEPS:\n"
        "1. Take a PHOTO of this screen\n"
        "2. Open the photo on your phone\n"
        "3. Tap the URL in the photo\n"
        "4. Authorize on Trakt\n"
        "5. Copy the code\n"
        "6. Come back here to enter it\n\n"
        "Click OK when ready to enter code"
    )
    
    get_trakt_code_simple()

LETTERBOXD_CACHE_FILE = xbmcvfs.translatePath(
    f"special://profile/addon_data/{ADDON_ID}/letterboxd_cache.json"
)

def parse_letterboxd_rss_kodi(username="tommhe", min_rating=4.0, limit=50):
    """Parse Letterboxd RSS and return a list of films with TMDB IDs"""
    try:
        log(f"Parsing Letterboxd RSS for user: {username}", xbmc.LOGDEBUG)
        rss_url = f"https://letterboxd.com/{username}/rss/"
        response = requests.get(rss_url, timeout=10, headers={'User-Agent': 'Kodi Addon'})
        if response.status_code != 200:
            log(f"Failed to fetch RSS: {response.status_code}", xbmc.LOGERROR)
            return []

        root = ET.fromstring(response.content)
        films = []

        for item in root.findall(".//item"):
            title = item.findtext("letterboxd:filmTitle", namespaces={'letterboxd': 'https://letterboxd.com'}) or ""
            year = item.findtext("letterboxd:filmYear", namespaces={'letterboxd': 'https://letterboxd.com'}) or ""
            rating_text = item.findtext("letterboxd:memberRating", namespaces={'letterboxd': 'https://letterboxd.com'}) or "0"
            try:
                rating = float(rating_text)
            except:
                rating = 0.0

            if rating < min_rating:
                continue

            tmdb_id = item.findtext("tmdb:movieId", namespaces={'tmdb': 'https://themoviedb.org'})
            if not tmdb_id:
                continue 

            link = item.findtext("link", "")

            films.append({
                "title": title.strip(),
                "year": year.strip(),
                "rating": rating,
                "source_id": f"tmdb:{tmdb_id}",
                "tmdb_id": tmdb_id,
                "url": link,
                "weighted_score": rating * 10
            })

            if len(films) >= limit:
                break

        log(f"Parsed {len(films)} films from RSS", xbmc.LOGDEBUG)
        return films

    except Exception as e:
        log(f"Error parsing Letterboxd RSS: {e}", xbmc.LOGERROR)
        return []

def get_letterboxd_favorites_cached(force_refresh=False):
    """Get Letterboxd favorites with TMDB IDs, cached locally."""
    if ADDON.getSetting("show_developer_favorites") != "true":
        log("Developer's Favourites is disabled", xbmc.LOGDEBUG)
        return []

    if not force_refresh and xbmcvfs.exists(LETTERBOXD_CACHE_FILE):
        try:
            with xbmcvfs.File(LETTERBOXD_CACHE_FILE, 'r') as f:
                cache_data = json.load(f)
            cache_age = time.time() - cache_data.get("timestamp", 0)
            if cache_age < 24 * 60 * 60:
                log(f"Using cached Letterboxd favorites (age {cache_age:.1f}s)", xbmc.LOGDEBUG)
                return cache_data.get("data", [])
        except Exception as e:
            log(f"Error reading Letterboxd cache: {e}", xbmc.LOGDEBUG)

    username = ADDON.getSetting("letterboxd_username") or "tommhe"
    min_rating = float(ADDON.getSetting("min_rating") or 4.0)
    limit = int(ADDON.getSetting("max_films") or 20)

    films = parse_letterboxd_rss_kodi(username=username, min_rating=min_rating, limit=limit)

    if films:
        cache_data = {
            "data": films,
            "timestamp": time.time(),
            "username": username,
            "source": "letterboxd_rss"
        }
        try:
            folder = xbmcvfs.translatePath(f"special://profile/addon_data/{ADDON_ID}")
            if not xbmcvfs.exists(folder):
                xbmcvfs.mkdirs(folder)
            with xbmcvfs.File(LETTERBOXD_CACHE_FILE, 'w') as f:
                json.dump(cache_data, f)
            log(f"Saved {len(films)} Letterboxd favorites to cache", xbmc.LOGDEBUG)
        except Exception as e:
            log(f"Error saving Letterboxd cache: {e}", xbmc.LOGDEBUG)

    return films

def show_developer_favorites():
    """Show Developer's Favourites fully playable with metadata"""
    handle = int(sys.argv[1])

    if ADDON.getSetting("show_developer_favorites") != "true":
        log("Developer's Favourites is disabled", xbmc.LOGDEBUG)
        return

    log("Loading Developer's Favourites", xbmc.LOGDEBUG)

    refresh_item = xbmcgui.ListItem(label="[B]↻ Refresh Favorites[/B]")
    refresh_item.setArt({'icon': 'DefaultFolder.png'})
    xbmcplugin.addDirectoryItem(
        handle,
        get_url(action="refresh_favorites"),
        refresh_item,
        isFolder=False
    )

    favorites = get_letterboxd_favorites_cached()
    if not favorites:
        li = xbmcgui.ListItem(label="No favorites found or error loading")
        li.setArt({'icon': 'DefaultFolder.png'})
        li.setInfo('video', {'title': "Error loading favorites"})
        xbmcplugin.addDirectoryItem(handle, "", li, isFolder=False)
        xbmcplugin.endOfDirectory(handle)
        return

    tmdb = TMDBClient()

    unique_films = {}
    for f in favorites:
        tmdb_id = f.get("tmdb_id")
        if tmdb_id:
            unique_films[tmdb_id] = f  

    films_list = list(unique_films.values())
    random.shuffle(films_list)  

    films_list = films_list[:20]

    final_films = []
    for film in films_list:
        title = film.get("title", "Unknown")
        year = film.get("year", "")
        rating = film.get("rating", 0)
        tmdb_id = film.get("tmdb_id")

        if not tmdb_id:
            continue

        try:
            media = tmdb.get_movie_details(tmdb_id)
            if not media:
                continue
        except Exception as e:
            log(f"Error fetching TMDB details for {title} ({tmdb_id}): {e}", xbmc.LOGDEBUG)
            continue

        imdb_id = media.get("imdb_id") or convert_tmdb_to_imdb(tmdb_id)
        if not imdb_id:
            continue

        film["_media"] = media
        film["_imdb_id"] = imdb_id
        final_films.append(film)

    for film in final_films:
        media = film["_media"]
        imdb_id = film["_imdb_id"]
        title = film.get("title", "Unknown")
        year = film.get("year", "")
        rating = film.get("rating", 0)

        label = f"{title} ({year})"
        if rating > 0:
            label += f" ★ {rating:.1f}"

        item = xbmcgui.ListItem(label=label)
        poster = build_image_url(media.get("poster_path"), POSTER_SIZE)
        fanart = build_image_url(media.get("backdrop_path"), BACKDROP_SIZE)

        item.setArt({
            'icon': poster or 'DefaultVideo.png',
            'thumb': poster or 'DefaultVideo.png',
            'poster': poster or 'DefaultVideo.png',
            'fanart': fanart or ADDON_PATH + "/fanart.jpg"
        })

        item.setInfo('video', {
            'title': title,
            'year': int(year) if year and year.isdigit() else 0,
            'plot': media.get("overview", ""),
            'rating': float(media.get("vote_average", 0))
        })

        url = get_url(action="play_movie", ttid=imdb_id, title=title)
        item.setProperty('IsPlayable', 'true')
        xbmcplugin.addDirectoryItem(handle, url, item, isFolder=False)

    xbmcplugin.setContent(handle, 'movies')
    xbmcplugin.endOfDirectory(handle, updateListing=True)

def refresh_favorites():
    """Force refresh of Letterboxd favorites and reload container."""
    handle = int(sys.argv[1])

    favorites = get_letterboxd_favorites_cached(force_refresh=True)
    xbmcgui.Dialog().notification(
        ADDON_NAME,
        f"Refreshed {len(favorites)} favorites",
        xbmcgui.NOTIFICATION_INFO,
        3000
    )

    show_developer_favorites()

def process_trakt_code(code):
    progress = xbmcgui.DialogProgress()
    progress.create(ADDON_NAME, "Linking Trakt account...")
    
    try:
        progress.update(25, "Validating code...")
        
        token_data = exchange_trakt_code(code)
        
        progress.update(100)
        progress.close()
        
        if token_data:
            username = token_data.get('username', 'N/A')
            ADDON.setSetting("trakt_username", username)
            
            xbmcgui.Dialog().ok(
                "Trakt Account Linked!",
                f"Successfully linked to:\n\n"
                f"{username}\n\n"
                "You can now access your Trakt watchlist."
            )
            
            xbmc.executebuiltin("Container.Refresh")
            
        else:
            xbmcgui.Dialog().ok(
                "Linking Failed",
                "Could not link Trakt account.\n\n"
                "Possible reasons:\n"
                "Code expired (get a new one)\n"
                "Network connection issue\n"
                "Invalid authorization code\n\n"
                "Try again with a fresh code from Trakt.tv"
            )
            
    except Exception as e:
        if progress:
            progress.close()
        
        log(f"Trakt linking error: {e}", xbmc.LOGERROR)
        xbmcgui.Dialog().ok(
            "Error",
            f"Trakt linking failed:\n\n{str(e)[:200]}"
        )

def get_trakt_code_simple():
    keyboard = xbmc.Keyboard()
    keyboard.setHeading("Enter Trakt Authorization Code")
    keyboard.doModal()
    
    if keyboard.isConfirmed():
        code = keyboard.getText()
        if code:
            process_trakt_code(code)
        else:
            xbmcgui.Dialog().notification(ADDON_NAME, "No code entered", xbmcgui.NOTIFICATION_WARNING)

def get_watch_history():
    """Load watch history from file"""
    if xbmcvfs.exists(WATCH_HISTORY_FILE):
        try:
            with xbmcvfs.File(WATCH_HISTORY_FILE, 'r') as f:
                return json.load(f)
        except Exception as e:
            log(f"Error loading watch history: {e}", xbmc.LOGDEBUG)
    return {"movies": [], "tv_episodes": []}

def save_watch_history(history):
    """Save watch history to file"""
    try:
        folder = xbmcvfs.translatePath(f"special://profile/addon_data/{ADDON_ID}")
        if not xbmcvfs.exists(folder):
            xbmcvfs.mkdirs(folder)
        
        with xbmcvfs.File(WATCH_HISTORY_FILE, 'w') as f:
            json.dump(history, f)
    except Exception as e:
        log(f"Error saving watch history: {e}", xbmc.LOGDEBUG)

def log_watch_history(media_id, media_type, title):
    """Log a watched item"""
    history = get_watch_history()
    timestamp = time.time()
    
    entry = {
        "id": media_id,
        "type": media_type,
        "title": title,
        "timestamp": timestamp,
        "date": time.strftime("%Y-%m-%d %H:%M:%S")
    }
    
    if media_type == "movie":
        history["movies"].append(entry)
    elif media_type == "tv_episode":
        history["tv_episodes"].append(entry)
    
    if len(history["movies"]) > 100:
        history["movies"] = history["movies"][-100:]
    if len(history["tv_episodes"]) > 100:
        history["tv_episodes"] = history["tv_episodes"][-100:]
    
    save_watch_history(history)
    log(f"Logged watch history: {title} ({media_type})", xbmc.LOGDEBUG)

def get_recommendations(media_id, media_type="movie", recommendation_type="r", num_recommendations=10):
    """Get recommendations from TMDB"""
    tmdb = TMDBClient()
    recommendations = []
    
    try:
        if media_type == "movie":
            if recommendation_type == "r":
                data = tmdb.get_movie_recommendations(media_id)
            else:
                data = tmdb.get_movie_similar(media_id)
        else:
            if recommendation_type == "r":
                data = tmdb.get_tv_recommendations(media_id)
            else:
                data = tmdb.get_tv_similar(media_id)
        
        if data and data.get("results"):
            for item in data["results"][:num_recommendations]:
                if media_type == "movie":
                    item_info = {
                        "id": item.get("id"),
                        "title": item.get("title"),
                        "year": item.get("release_date", "")[:4] if item.get("release_date") else "",
                        "type": "movie",
                        "poster": item.get("poster_path"),
                        "backdrop": item.get("backdrop_path"),
                        "rating": item.get("vote_average", 0),
                        "overview": item.get("overview", "")
                    }
                else:
                    item_info = {
                        "id": item.get("id"),
                        "title": item.get("name"),
                        "year": item.get("first_air_date", "")[:4] if item.get("first_air_date") else "",
                        "type": "tv",
                        "poster": item.get("poster_path"),
                        "backdrop": item.get("backdrop_path"),
                        "rating": item.get("vote_average", 0),
                        "overview": item.get("overview", "")
                    }
                recommendations.append(item_info)
    
    except Exception as e:
        log(f"Error getting recommendations: {e}", xbmc.LOGERROR)
    
    return recommendations

def show_similar_content(media_type, media_id):
    """Show similar content for a media item"""
    if not is_paid_user():
        xbmcgui.Dialog().notification(ADDON_NAME, "Paid feature only", xbmcgui.NOTIFICATION_ERROR)
        return
    
    handle = int(sys.argv[1])
    recommendations = get_recommendations(media_id, media_type, "s", 20)
    
    if not recommendations:
        xbmcgui.Dialog().notification(ADDON_NAME, "No similar content found", xbmcgui.NOTIFICATION_INFO)
        xbmcplugin.endOfDirectory(handle)
        return
    
    for item in recommendations:
        label = f"{item['title']} ({item['year']})" if item['year'] else item['title']
        
        if item['type'] == "movie":
            url = get_url(action="movie_details", id=item["id"])
            media_info = {'mediatype': 'movie'}
        else:
            url = get_url(action="tv_details", id=item["id"])
            media_info = {'mediatype': 'tvshow'}
        
        li = xbmcgui.ListItem(label=label)
        
        poster = build_image_url(item.get("poster"), POSTER_SIZE)
        fanart = build_image_url(item.get("backdrop"), BACKDROP_SIZE)
        
        li.setArt({
            'icon': poster or 'DefaultVideo.png',
            'thumb': poster or 'DefaultVideo.png',
            'poster': poster or 'DefaultVideo.png',
            'fanart': fanart or ADDON_PATH + "/fanart.jpg"
        })
        
        info = {
            'title': item['title'],
            'year': int(item['year']) if item['year'] and item['year'].isdigit() else 0,
            'plot': item.get("overview", ""),
            'rating': float(item.get("rating", 0))
        }
        info.update(media_info)
        li.setInfo('video', info)
        
        xbmcplugin.addDirectoryItem(handle, url, li, isFolder=True)
    
    xbmcplugin.setContent(handle, 'movies' if media_type == 'movie' else 'tvshows')
    xbmcplugin.endOfDirectory(handle)

def show_your_next_watch():
    """Show recommended content based on watch history"""
    if not is_paid_user():
        xbmcgui.Dialog().notification(ADDON_NAME, "Paid feature only", xbmcgui.NOTIFICATION_ERROR)
        return
    
    handle = int(sys.argv[1])
    tmdb_ids = get_tmdb_ids_from_history()
    
    if not tmdb_ids:
        li = xbmcgui.ListItem(label="No watch history yet")
        li.setArt({'icon': 'DefaultFolder.png'})
        li.setInfo('video', {'title': "No watch history yet"})
        xbmcplugin.addDirectoryItem(handle, "", li, isFolder=False)
        xbmcplugin.endOfDirectory(handle)
        return

    watched_ids = set(tmdb_ids)
    
    all_recommendations = []
    for tmdb_id in tmdb_ids[-10:]: 
        clean_id = str(tmdb_id)
        media_type = "movie"
        
        if "/" in clean_id:
            media_type = "tv"
            clean_id = clean_id.split("/")[1]
        
        try:
            log(f"Getting recommendations for {media_type} ID: {clean_id}", xbmc.LOGDEBUG)
            recommendations = get_recommendations(clean_id, media_type, "r", 10)  # Get 10 each
            log(f"Got {len(recommendations)} recommendations for {clean_id}", xbmc.LOGDEBUG)
            all_recommendations.extend(recommendations)
        except Exception as e:
            log(f"Error getting recommendations for {clean_id}: {e}", xbmc.LOGDEBUG)
            continue
    
    if not all_recommendations:
        li = xbmcgui.ListItem(label="No recommendations found")
        li.setArt({'icon': 'DefaultFolder.png'})
        li.setInfo('video', {'title': "No recommendations found"})
        xbmcplugin.addDirectoryItem(handle, "", li, isFolder=False)
        xbmcplugin.endOfDirectory(handle)
        return
    
    freq = {}
    for rec in all_recommendations:
        if not rec or 'id' not in rec:
            continue
            
        key = f"{rec['type']}_{rec['id']}"
        
        if str(rec['id']) in watched_ids:
            continue
            
        weight = 1
        rating = rec.get('rating', 0)
        if rating > 7.0:
            weight *= 2 
        elif rating > 8.0:
            weight *= 3  
        
        freq[key] = freq.get(key, 0) + weight
    
    if not freq:
        li = xbmcgui.ListItem(label="Try watching more content to get recommendations")
        li.setArt({'icon': 'DefaultFolder.png'})
        li.setInfo('video', {'title': "Need more watch history"})
        xbmcplugin.addDirectoryItem(handle, "", li, isFolder=False)
        xbmcplugin.endOfDirectory(handle)
        return
    
    top_items = sorted(freq.items(), key=lambda x: x[1], reverse=True)[:20]
    
    displayed_items = set()
    
    for key, count in top_items:
        parts = key.split("_")
        if len(parts) < 2:
            continue
            
        rec_type = parts[0]
        rec_id = parts[1]
        
        if rec_id in displayed_items:
            continue
            
        rec_data = None
        for rec in all_recommendations:
            if str(rec.get('id')) == rec_id and rec.get('type') == rec_type:
                rec_data = rec
                break
        
        if rec_data:
            displayed_items.add(rec_id)
            
            title = rec_data.get('title', 'Unknown')
            year = rec_data.get('year', '')
            rating = rec_data.get('rating', 0)
            plot = rec_data.get('overview', '')
            
            label = f"{title}"
            if year:
                label += f" ({year})"
            if rating > 0:
                label += f" ★ {rating:.1f}"
            
            if rec_type == "movie":
                url = get_url(action="movie_details", id=rec_data["id"])
                media_info = {'mediatype': 'movie'}
            else:
                url = get_url(action="tv_details", id=rec_data["id"])
                media_info = {'mediatype': 'tvshow'}
            
            li = xbmcgui.ListItem(label=label)
            
            poster = build_image_url(rec_data.get("poster"), POSTER_SIZE)
            fanart = build_image_url(rec_data.get("backdrop"), BACKDROP_SIZE)
            
            li.setArt({
                'icon': poster or 'DefaultVideo.png',
                'thumb': poster or 'DefaultVideo.png',
                'poster': poster or 'DefaultVideo.png',
                'fanart': fanart or ADDON_PATH + "/fanart.jpg"
            })
            
            info = {
                'title': title,
                'year': int(year) if year and year.isdigit() else 0,
                'plot': plot,
                'rating': float(rating) if rating > 0 else 0
            }
            info.update(media_info)
            li.setInfo('video', info)
            
            xbmcplugin.addDirectoryItem(handle, url, li, isFolder=True)
    
    if len(displayed_items) == 0:
        li = xbmcgui.ListItem(label="No new recommendations found")
        li.setArt({'icon': 'DefaultFolder.png'})
        li.setInfo('video', {'title': "No new recommendations found"})
        xbmcplugin.addDirectoryItem(handle, "", li, isFolder=False)
    
    xbmcplugin.setContent(handle, 'videos')
    xbmcplugin.endOfDirectory(handle)

def main_menu():
    handle = int(sys.argv[1])

    li = xbmcgui.ListItem("Movies")
    url = get_url(action="movies")
    xbmcplugin.addDirectoryItem(handle, url, li, isFolder=True)

    li = xbmcgui.ListItem("TV Shows")
    url = get_url(action="tv_shows")
    xbmcplugin.addDirectoryItem(handle, url, li, isFolder=True)

    li = xbmcgui.ListItem("Search")
    url = get_url(action="search")
    xbmcplugin.addDirectoryItem(handle, url, li, isFolder=True)

    if is_paid_user():
        headers = get_trakt_headers()
        if headers:
            li = xbmcgui.ListItem("Trakt Watchlist")
            url = get_url(action="trakt_watchlist")
        else:
            li = xbmcgui.ListItem("Link Trakt Account")
            url = get_url(action="trakt_link")  
        li.setArt({'icon': 'DefaultFolder.png', 'thumb': 'DefaultFolder.png'})
        li.setInfo('video', {'title': li.getLabel()})
        xbmcplugin.addDirectoryItem(handle, url, li, isFolder=True)
    
        li = xbmcgui.ListItem("Your Next Watch")
        url = get_url(action="your_next_watch")
        li.setArt({'icon': 'DefaultFolder.png', 'thumb': 'DefaultFolder.png'})
        li.setInfo('video', {'title': "Your Next Watch"})
        xbmcplugin.addDirectoryItem(handle, url, li, isFolder=True)

        if ADDON.getSetting("show_developer_favorites") == "true":
            url = get_url(action="developer_favorites")
            list_item = xbmcgui.ListItem(label="LetterBoxd's Favourites")
            list_item.setArt({'icon': 'DefaultFolder.png', 'thumb': 'DefaultFolder.png'})
            list_item.setInfo('video', {'title': "Developer's Favourites"})
            xbmcplugin.addDirectoryItem(handle, url, list_item, isFolder=True)


    xbmcplugin.endOfDirectory(handle)

def movies_menu():
    handle = int(sys.argv[1])
    
    categories = [
        ("Popular", "movie_popular"),
        ("Top Rated", "movie_top_rated"),
        ("Now Playing", "movie_now_playing"),
        ("Upcoming", "movie_upcoming"),
        ("Trending", "movie_trending"),  
        ("Genres", "movie_genres")
    ]
    
    for label, action in categories:
        url = get_url(action=action)
        list_item = xbmcgui.ListItem(label=label)
        list_item.setArt({'icon': 'DefaultFolder.png', 'thumb': 'DefaultFolder.png'})
        list_item.setInfo('video', {'title': label})
        xbmcplugin.addDirectoryItem(handle, url, list_item, isFolder=True)
    
    xbmcplugin.setContent(handle, 'files')
    xbmcplugin.endOfDirectory(handle)

def tv_shows_menu():
    handle = int(sys.argv[1])
    
    categories = [
        ("Popular", "tv_popular"),
        ("Top Rated", "tv_top_rated"),
        ("On Air", "tv_on_air"),
        ("Airing Today", "tv_airing_today"),  
        ("Trending", "tv_trending"),          
        ("Genres", "tv_genres")
    ]
    
    for label, action in categories:
        url = get_url(action=action)
        list_item = xbmcgui.ListItem(label=label)
        list_item.setArt({'icon': 'DefaultFolder.png', 'thumb': 'DefaultFolder.png'})
        list_item.setInfo('video', {'title': label})
        xbmcplugin.addDirectoryItem(handle, url, list_item, isFolder=True)
    
    xbmcplugin.setContent(handle, 'files')
    xbmcplugin.endOfDirectory(handle)

def list_movies(action, page=1):
    handle = int(sys.argv[1])
    tmdb = TMDBClient()
    
    action_map = {
        "movie_popular": tmdb.get_popular_movies,
        "movie_top_rated": tmdb.get_top_rated_movies,
        "movie_now_playing": tmdb.get_now_playing_movies,
        "movie_upcoming": tmdb.get_upcoming_movies,
        "movie_trending": tmdb.get_trending_movies  
    }
    
    if action in action_map:
        data = action_map[action](page)
        if data and data.get("results"):
            movies = data["results"]
            
            scored_movies = []
            for movie in movies:
                vote_average = movie.get("vote_average", 0)
                vote_count = movie.get("vote_count", 0)
                popularity = movie.get("popularity", 0)
                
                import math
                if vote_count > 0:
                    vote_weight = min(1.0, math.log(vote_count + 1) / math.log(1000))
                else:
                    vote_weight = 0
                
                popularity_bonus = min(0.3, popularity / 100)
                weighted_score = vote_average * (0.7 + 0.3 * vote_weight) + popularity_bonus
                
                has_poster = bool(movie.get("poster_path"))
                has_year = bool(movie.get("release_date"))
                
                if (vote_count > 50) or (popularity > 5) or (has_poster and has_year):
                    scored_movies.append({
                        'movie': movie,
                        'weighted_score': weighted_score
                    })
            
            scored_movies.sort(key=lambda x: x['weighted_score'], reverse=True)
            
            for scored in scored_movies:
                movie = scored['movie']
                title = movie.get("title", "Unknown")
                year = movie.get("release_date", "")[:4] if movie.get("release_date") else ""
                rating = movie.get("vote_average", 0)
                vote_count = movie.get("vote_count", 0)
                
                label = f"{title}"
                if year:
                    label += f" ({year})"
                if rating > 0 and vote_count > 10:
                    label += f" ★ {rating:.1f}"
                
                url = get_url(action="movie_details", id=movie["id"])
                
                list_item = xbmcgui.ListItem(label=label)
                poster = build_image_url(movie.get("poster_path"), POSTER_SIZE)
                fanart = build_image_url(movie.get("backdrop_path"), BACKDROP_SIZE)
                art = {'icon': poster, 'thumb': poster, 'poster': poster, 'fanart': fanart or ADDON_PATH + "/fanart.jpg"}
                list_item.setArt(art)
                
                info = {'title': title, 'year': int(year) if year.isdigit() else 0,
                        'plot': movie.get("overview", ""), 'rating': float(movie.get("vote_average", 0))}
                list_item.setInfo('video', info)
                
                xbmcplugin.addDirectoryItem(handle, url, list_item, isFolder=True)
            
            if data.get("total_pages", 0) > page:
                next_url = get_url(action=action, page=page + 1)
                next_item = xbmcgui.ListItem(label="Next Page")
                next_item.setArt({'icon': 'DefaultFolder.png'})
                xbmcplugin.addDirectoryItem(handle, next_url, next_item, isFolder=True)
    
    xbmcplugin.setContent(handle, 'movies')
    xbmcplugin.endOfDirectory(handle)

def list_tv_shows(action, page=1):
    handle = int(sys.argv[1])
    tmdb = TMDBClient()
    
    action_map = {
        "tv_popular": tmdb.get_popular_tv,
        "tv_top_rated": tmdb.get_top_rated_tv,
        "tv_on_air": tmdb.get_tv_on_air,
        "tv_airing_today": tmdb.get_tv_airing_today,  
        "tv_trending": tmdb.get_trending_tv         
    }
    
    if action in action_map:
        data = action_map[action](page)
        if data and data.get("results"):
            tv_shows = data["results"]
            
            scored_shows = []
            for tv in tv_shows:
                vote_average = tv.get("vote_average", 0)
                vote_count = tv.get("vote_count", 0)
                popularity = tv.get("popularity", 0)
                
                import math
                if vote_count > 0:
                    vote_weight = min(1.0, math.log(vote_count + 1) / math.log(1000))
                else:
                    vote_weight = 0
                
                popularity_bonus = min(0.3, popularity / 100)
                weighted_score = vote_average * (0.7 + 0.3 * vote_weight) + popularity_bonus
                
                has_poster = bool(tv.get("poster_path"))
                has_year = bool(tv.get("first_air_date"))
                
                if (vote_count > 50) or (popularity > 5) or (has_poster and has_year):
                    scored_shows.append({
                        'tv': tv,
                        'weighted_score': weighted_score,
                        'vote_count': vote_count,
                        'popularity': popularity,
                        'has_poster': has_poster
                    })
            
            scored_shows.sort(key=lambda x: x['weighted_score'], reverse=True)
            
            if len(scored_shows) < 5:
                scored_shows = []
                for tv in tv_shows:
                    scored_shows.append({
                        'tv': tv,
                        'weighted_score': tv.get("vote_average", 0),
                        'vote_count': tv.get("vote_count", 0),
                        'popularity': tv.get("popularity", 0),
                        'has_poster': bool(tv.get("poster_path"))
                    })
                scored_shows.sort(key=lambda x: x['weighted_score'], reverse=True)
            
            for scored in scored_shows:
                tv = scored['tv']
                title = tv.get("name", "Unknown")
                year = tv.get("first_air_date", "")[:4] if tv.get("first_air_date") else ""
                rating = tv.get("vote_average", 0)
                vote_count = tv.get("vote_count", 0)
                
                label = f"{title}"
                if year:
                    label += f" ({year})"
                if rating > 0 and vote_count > 10:
                    label += f" ★ {rating:.1f}"
                
                url = get_url(action="tv_details", id=tv["id"])
                
                list_item = xbmcgui.ListItem(label=label)
                poster = build_image_url(tv.get("poster_path"), POSTER_SIZE)
                fanart = build_image_url(tv.get("backdrop_path"), BACKDROP_SIZE)
                art = {'icon': poster, 'thumb': poster, 'poster': poster, 'fanart': fanart or ADDON_PATH + "/fanart.jpg"}
                list_item.setArt(art)
                
                info = {
                    'title': title, 
                    'year': int(year) if year.isdigit() else 0,
                    'plot': tv.get("overview", ""), 
                    'rating': float(tv.get("vote_average", 0)),
                    'mediatype': 'tvshow'
                }
                list_item.setInfo('video', info)
                
                xbmcplugin.addDirectoryItem(handle, url, list_item, isFolder=True)
            
            if data.get("total_pages", 0) > page:
                next_url = get_url(action=action, page=page + 1)
                next_item = xbmcgui.ListItem(label="Next Page")
                next_item.setArt({'icon': 'DefaultFolder.png'})
                xbmcplugin.addDirectoryItem(handle, next_url, next_item, isFolder=True)
    
    xbmcplugin.setContent(handle, 'tvshows')
    xbmcplugin.endOfDirectory(handle)

def movie_genres():
    handle = int(sys.argv[1])
    tmdb = TMDBClient()
    
    genres = tmdb.get_movie_genres()
    
    for genre in genres:
        url = get_url(action="movie_genre", id=genre["id"], name=genre["name"])
        list_item = xbmcgui.ListItem(label=genre["name"])
        list_item.setArt({'icon': 'DefaultFolder.png'})
        list_item.setInfo('video', {'title': genre["name"]})
        xbmcplugin.addDirectoryItem(handle, url, list_item, isFolder=True)
    
    xbmcplugin.setContent(handle, 'files')
    xbmcplugin.endOfDirectory(handle)

def tv_genres():
    handle = int(sys.argv[1])
    tmdb = TMDBClient()
    
    genres = tmdb.get_tv_genres()
    
    for genre in genres:
        url = get_url(action="tv_genre", id=genre["id"], name=genre["name"])
        list_item = xbmcgui.ListItem(label=genre["name"])
        list_item.setArt({'icon': 'DefaultFolder.png'})
        list_item.setInfo('video', {'title': genre["name"]})
        xbmcplugin.addDirectoryItem(handle, url, list_item, isFolder=True)
    
    xbmcplugin.setContent(handle, 'files')
    xbmcplugin.endOfDirectory(handle)

def movies_by_genre(genre_id, page=1, genre_name=""):
    handle = int(sys.argv[1])
    tmdb = TMDBClient()
    
    data = tmdb.get_movies_by_genre(genre_id, page)
    
    xbmcplugin.setPluginCategory(handle, f"Movies - {genre_name}" if genre_name else "Movies")
    
    if data and data.get("results"):
        movies = data["results"]
        
        scored_movies = []
        for movie in movies:
            vote_average = movie.get("vote_average", 0)
            vote_count = movie.get("vote_count", 0)
            popularity = movie.get("popularity", 0)
            
            import math
            if vote_count > 0:
                vote_weight = min(1.0, math.log(vote_count + 1) / math.log(1000))
            else:
                vote_weight = 0
            
            popularity_bonus = min(0.3, popularity / 100)  
            
            weighted_score = vote_average * (0.7 + 0.3 * vote_weight) + popularity_bonus
            
            has_poster = bool(movie.get("poster_path"))
            has_year = bool(movie.get("release_date"))
            
            if (vote_count > 50) or (popularity > 5) or (has_poster and has_year):
                scored_movies.append({
                    'movie': movie,
                    'weighted_score': weighted_score,
                    'vote_count': vote_count,
                    'popularity': popularity,
                    'has_poster': has_poster
                })
        
        scored_movies.sort(key=lambda x: x['weighted_score'], reverse=True)

        if len(scored_movies) < 5:
            scored_movies = []
            for movie in movies:
                scored_movies.append({
                    'movie': movie,
                    'weighted_score': movie.get("vote_average", 0),
                    'vote_count': movie.get("vote_count", 0),
                    'popularity': movie.get("popularity", 0),
                    'has_poster': bool(movie.get("poster_path"))
                })
            scored_movies.sort(key=lambda x: x['weighted_score'], reverse=True)
        
        for scored in scored_movies:
            movie = scored['movie']
            title = movie.get("title", "Unknown")
            year = movie.get("release_date", "")[:4] if movie.get("release_date") else ""
            rating = movie.get("vote_average", 0)
            vote_count = movie.get("vote_count", 0)
            
            label = f"{title}"
            if year:
                label += f" ({year})"
            if rating > 0 and vote_count > 10:
                label += f" ★ {rating:.1f}"
            
            url = get_url(action="movie_details", id=movie["id"])
            list_item = xbmcgui.ListItem(label=label)
            
            poster = build_image_url(movie.get("poster_path"), POSTER_SIZE)
            fanart = build_image_url(movie.get("backdrop_path"), BACKDROP_SIZE)
            
            art = {
                'icon': poster,
                'thumb': poster,
                'poster': poster,
                'fanart': fanart or ADDON_PATH + "/fanart.jpg"
            }
            list_item.setArt(art)
            
            info = {
                'title': title,
                'year': int(year) if year.isdigit() else 0,
                'plot': movie.get("overview", ""),
                'rating': float(rating) if rating > 0 else 0,
                'votes': str(vote_count) if vote_count > 0 else ""
            }
            list_item.setInfo('video', info)
            
            xbmcplugin.addDirectoryItem(handle, url, list_item, isFolder=True)
        
        total_pages = data.get("total_pages", 0)
        
        if total_pages > page:
            next_url = get_url(action="movie_genre", id=genre_id, page=page + 1, name=genre_name)
            next_item = xbmcgui.ListItem(label=f"Page {page + 1} of {total_pages}")
            next_item.setArt({'icon': 'DefaultFolder.png'})
            next_item.setInfo('video', {'title': f"Next Page ({page + 1}/{total_pages})"})
            xbmcplugin.addDirectoryItem(handle, next_url, next_item, isFolder=True)
    
    xbmcplugin.setContent(handle, 'movies')
    xbmcplugin.endOfDirectory(handle)

def tv_by_genre(genre_id, page=1, genre_name=""):
    handle = int(sys.argv[1])
    tmdb = TMDBClient()
    
    data = tmdb.get_tv_by_genre(genre_id, page)
    
    xbmcplugin.setPluginCategory(handle, f"TV Shows - {genre_name}" if genre_name else "TV Shows")
    
    if data and data.get("results"):
        tv_shows = data["results"]
        
        scored_shows = []
        for tv in tv_shows:
            vote_average = tv.get("vote_average", 0)
            vote_count = tv.get("vote_count", 0)
            popularity = tv.get("popularity", 0)
            
            import math
            if vote_count > 0:
                vote_weight = min(1.0, math.log(vote_count + 1) / math.log(1000))
            else:
                vote_weight = 0
            
            popularity_bonus = min(0.3, popularity / 100)
            weighted_score = vote_average * (0.7 + 0.3 * vote_weight) + popularity_bonus
            
            has_poster = bool(tv.get("poster_path"))
            has_year = bool(tv.get("first_air_date"))
            
            if (vote_count > 50) or (popularity > 5) or (has_poster and has_year):
                scored_shows.append({
                    'tv': tv,
                    'weighted_score': weighted_score,
                    'vote_count': vote_count,
                    'popularity': popularity,
                    'has_poster': has_poster
                })
        
        scored_shows.sort(key=lambda x: x['weighted_score'], reverse=True)

        if len(scored_shows) < 5:
            scored_shows = []
            for tv in tv_shows:
                scored_shows.append({
                    'tv': tv,
                    'weighted_score': tv.get("vote_average", 0),
                    'vote_count': tv.get("vote_count", 0),
                    'popularity': tv.get("popularity", 0),
                    'has_poster': bool(tv.get("poster_path"))
                })
            scored_shows.sort(key=lambda x: x['weighted_score'], reverse=True)
        
        for scored in scored_shows:
            tv = scored['tv']
            title = tv.get("name", "Unknown")
            year = tv.get("first_air_date", "")[:4] if tv.get("first_air_date") else ""
            rating = tv.get("vote_average", 0)
            vote_count = tv.get("vote_count", 0)
            
            label = f"{title}"
            if year:
                label += f" ({year})"
            if rating > 0 and vote_count > 10:
                label += f" ★ {rating:.1f}"
            
            url = get_url(action="tv_details", id=tv["id"])
            list_item = xbmcgui.ListItem(label=label)
            
            poster = build_image_url(tv.get("poster_path"), POSTER_SIZE)
            fanart = build_image_url(tv.get("backdrop_path"), BACKDROP_SIZE)
            
            art = {
                'icon': poster,
                'thumb': poster,
                'poster': poster,
                'fanart': fanart or ADDON_PATH + "/fanart.jpg"
            }
            list_item.setArt(art)
            
            info = {
                'title': title,
                'year': int(year) if year.isdigit() else 0,
                'plot': tv.get("overview", ""),
                'rating': float(rating) if rating > 0 else 0,
                'votes': str(vote_count) if vote_count > 0 else "",
                'mediatype': 'tvshow'
            }
            list_item.setInfo('video', info)
            
            xbmcplugin.addDirectoryItem(handle, url, list_item, isFolder=True)
        
        total_pages = data.get("total_pages", 0)
        
        if total_pages > page:
            next_url = get_url(action="tv_genre", id=genre_id, page=page + 1, name=genre_name)
            next_item = xbmcgui.ListItem(label=f"Page {page + 1} of {total_pages}")
            next_item.setArt({'icon': 'DefaultFolder.png'})
            next_item.setInfo('video', {'title': f"Next Page ({page + 1}/{total_pages})"})
            xbmcplugin.addDirectoryItem(handle, next_url, next_item, isFolder=True)
    
    xbmcplugin.setContent(handle, 'tvshows')
    xbmcplugin.endOfDirectory(handle)

def season_episodes(tv_id, season_num, show_title=""):
    handle = int(sys.argv[1])
    tmdb = TMDBClient()
    
    season = tmdb.get_season_details(tv_id, season_num)
    
    if season and season.get("episodes"):
        for episode in season["episodes"]:
            ep_num = episode.get("episode_number", 1)
            title = episode.get("name", f"Episode {ep_num}")
            label = f"{ep_num}. {title}"
            
            play_url = get_url(
                action="play_tv", 
                tv_id=tv_id,
                season=season_num,
                episode=ep_num,
                title=f"{show_title} - S{season_num}E{ep_num}: {title}"
            )
            
            item = xbmcgui.ListItem(label=label)
            
            still = build_image_url(episode.get("still_path"), "w500")
            fanart = build_image_url(season.get("poster_path") or episode.get("still_path"), BACKDROP_SIZE)
            
            art = {
                'icon': still or 'DefaultVideo.png',
                'thumb': still or 'DefaultVideo.png',
                'fanart': fanart or ADDON_PATH + "/fanart.jpg"
            }
            item.setArt(art)
            
            info = {
                'title': title,
                'plot': episode.get("overview", ""),
                'episode': ep_num,
                'season': season_num,
                'tvshowtitle': show_title,
                'aired': episode.get("air_date", "")
            }
            item.setInfo('video', info)
            item.setProperty('IsPlayable', 'true')
            
            xbmcplugin.addDirectoryItem(handle, play_url, item, isFolder=False)
    
    xbmcplugin.setContent(handle, 'episodes')
    xbmcplugin.endOfDirectory(handle)

def search_menu():
    """Show search options including actor search"""
    dialog = xbmcgui.Dialog()
    choice = dialog.select("Search in:", ["Movies", "TV Shows", "Actors/Directors"])
    
    if choice == 0:
        keyboard = xbmc.Keyboard()
        keyboard.setHeading("Search for Movies")
        keyboard.doModal()
        if keyboard.isConfirmed():
            query = keyboard.getText()
            if query:
                perform_search(query, "movie")
    elif choice == 1:
        keyboard = xbmc.Keyboard()
        keyboard.setHeading("Search for TV Shows")
        keyboard.doModal()
        if keyboard.isConfirmed():
            query = keyboard.getText()
            if query:
                perform_search(query, "tv")
    elif choice == 2:
        search_actor_menu()

def perform_search(query, search_type, page=1):
    handle = int(sys.argv[1])
    tmdb = TMDBClient()
    
    if search_type == "movie":
        data = tmdb.search_movies(query, page)
        item_type = "movies"
    else:
        data = tmdb.search_tv(query, page)
        item_type = "tvshows"
    
    if data and data.get("results"):
        for item in data["results"]:
            if search_type == "movie":
                title = item.get("title", "Unknown")
                year = item.get("release_date", "")[:4] if item.get("release_date") else ""
                label = f"{title} ({year})" if year else title
                action = "movie_details"
                poster_path = item.get("poster_path")
            else:
                title = item.get("name", "Unknown")
                year = item.get("first_air_date", "")[:4] if item.get("first_air_date") else ""
                label = f"{title} ({year})" if year else title
                action = "tv_details"
                poster_path = item.get("poster_path")
            
            url = get_url(action=action, id=item["id"])
            list_item = xbmcgui.ListItem(label=label)
            
            poster = build_image_url(poster_path, POSTER_SIZE)
            fanart = build_image_url(item.get("backdrop_path"), BACKDROP_SIZE)
            
            art = {
                'icon': poster,
                'thumb': poster,
                'poster': poster,
                'fanart': fanart or ADDON_PATH + "/fanart.jpg"
            }
            list_item.setArt(art)
            
            info = {
                'title': title,
                'year': int(year) if year.isdigit() else 0,
                'plot': item.get("overview", ""),
                'rating': float(item.get("vote_average", 0))
            }
            list_item.setInfo('video', info)
            
            xbmcplugin.addDirectoryItem(handle, url, list_item, isFolder=True)
    
    xbmcplugin.setContent(handle, item_type)
    xbmcplugin.endOfDirectory(handle)

def router(paramstring):
    params = dict(urllib.parse.parse_qsl(paramstring))
    
    action = params.get("action", "main")
    page = int(params.get("page", 1))
    
    if action == "main":
        main_menu()
    elif action == "movies":
        movies_menu()
    elif action == "trakt_watchlist":
        trakt_watchlist(page)
    elif action == "trakt_link":  
        link_trakt_account() 
    elif action == "tv_shows":
        tv_shows_menu()
    elif action == "movie_popular":
        list_movies("movie_popular", page)
    elif action == "movie_top_rated":
        list_movies("movie_top_rated", page)
    elif action == "movie_now_playing":
        list_movies("movie_now_playing", page)
    elif action == "movie_upcoming":
        list_movies("movie_upcoming", page) 
    elif action == "movie_genres":
        movie_genres()
    elif action == "movie_genre":
        movies_by_genre(params.get("id"), page, params.get("name", ""))
    elif action == "tv_popular":
        list_tv_shows("tv_popular", page)
    elif action == "tv_top_rated":
        list_tv_shows("tv_top_rated", page)
    elif action == "tv_on_air":
        list_tv_shows("tv_on_air", page)
    elif action == "tv_genres":
        tv_genres()
    elif action == "tv_genre":
        tv_by_genre(params.get("id"), page, params.get("name", ""))
    elif action == "movie_trending":
        list_movies("movie_trending", int(params.get("page", 1)))
    elif action == "tv_trending":
        list_tv_shows("tv_trending", int(params.get("page", 1)))
    elif action == "tv_airing_today":
        list_tv_shows("tv_airing_today", int(params.get("page", 1)))
    elif action == "season_episodes":
        season_episodes(
            params.get("id"), 
            int(params.get("season", 1)),
            params.get("show_title", "")
        )
    elif action == "search":
        search_menu()
    elif action == "play_movie":
        play_stream(
            params.get("ttid"), 
            params.get("title", "Movie"),
            from_watchlist=params.get("from_watchlist", "false")
        )
    elif action == "play_tv":
        play_tv_stream(
            params.get("tv_id"),
            int(params.get("season", 1)),
            int(params.get("episode", 1)),
            params.get("title", "TV Episode"),
            from_watchlist=params.get("from_watchlist", "false")
        )
    elif action == "play_movie_subs":
        play_stream_with_subs(
            params.get("ttid"),
            params.get("title", "Movie"),
            from_watchlist=params.get("from_watchlist", "false")
        )
    elif action == "play_tv_subs":
        play_tv_stream_with_subs(
            params.get("tv_id"),
            int(params.get("season", 1)),
            int(params.get("episode", 1)),
            params.get("title", "TV Episode")
        )
    elif action == "movie_details":
        enhanced_media_details("movie", params.get("id"))
    elif action == "tv_details":
        enhanced_media_details("tv", params.get("id"))
    elif action == "season_episodes":
        enhanced_season_episodes(
            params.get("id"), 
            int(params.get("season", 1)),
            params.get("show_title", "")
        )
    elif action == "episode_details":  
        enhanced_episode_details(
            params.get("tv_id"),
            int(params.get("season", 1)),
            int(params.get("episode", 1)),
            params.get("show_title", "")
        )
    elif action == "trakt_add_watchlist":
        imdb_id = params.get("imdb_id")
        if imdb_id:
            success = trakt_add_to_watchlist_simple(imdb_id)
            if success:
                xbmc.executebuiltin("Container.Refresh()")
    elif action == "trakt_remove_watchlist":
        imdb_id = params.get("imdb_id")
        if imdb_id:
            success = trakt_remove_from_watchlist_simple(imdb_id)
            if success:
                xbmc.executebuiltin("Container.Refresh()")
    elif action == "trakt_add_tv_watchlist":
        tvdb_id = params.get("tvdb_id")
        if tvdb_id:
            success = trakt_add_tv_to_watchlist_simple(tvdb_id)
            if success:
                xbmc.executebuiltin("Container.Refresh()")
    elif action == "trakt_remove_tv_watchlist":
        tvdb_id = params.get("tvdb_id")
        if tvdb_id:
            success = trakt_remove_tv_from_watchlist_simple(tvdb_id)
            if success:
                xbmc.executebuiltin("Container.Refresh()")
    elif action == "similar":
        show_similar_content(
            params.get("media_type"),
            params.get("id")
        )
    elif action == "your_next_watch":
        show_your_next_watch()
    elif action == "actor_search":
        perform_actor_search(params.get("query"), page)
    elif action == "actor_details":
        show_actor_details(params.get("id"))
    elif action == "developer_favorites":
        show_developer_favorites()
    elif action == 'refresh_favorites':
        refresh_favorites()
    elif action == "play_trailer":
        play_youtube_trailer(
        params.get("youtube_id"),
        params.get("title", "Trailer")
    )
    else:
        main_menu()

if __name__ == "__main__":
    router(sys.argv[2][1:])