import cherrypy
import requests
import os
import math
import pycountry
import json
import re
import threading
import time
import urllib.request
import xml.etree.ElementTree as ET
from PyMovieDb import IMDB
import subprocess
import yt_dlp
from downloadScript import download
imdb = IMDB()
top_movies = []
recent_movies = []

priorities = [
    {"type": "web", "video_codec": "x264"},
    {"type": "web", "video_codec": "x265"},
    {"type": "bluray", "video_codec": "x264"},
    {"type": "bluray", "video_codec": "x265"},
]

def createMoviePoster(json_format):
    movie_data = json_format
    movie_readout = ""
    plex_movies = json.load(open('/mnt/moviehub/plex_movies.json', 'r'))
    for movie in movie_data:
        res720 = {}
        res1080 = {}
        resOther = {}
        availableRes = []
        downButton = ""
        plex_server_resolution = []
        title = movie["title_english"]
        rating = movie["rating"]
        year = movie["year"]
        imdb = movie["imdb_code"]
        language = pycountry.languages.get(alpha_2=movie['language'])
        language = language.name if language is not None else language
        poster_url = movie["large_cover_image"]
        for movie_match in plex_movies["movies"]:
            if str(movie_match["video"]["title"].lower()) == str(movie["title"].lower()) and abs(int(movie_match["video"]["year"]) - year) <= 1:
                plex_server_resolution.append(movie_match["media"]["videoResolution"]+"p")
        for priority in priorities:
            for resolution in movie["torrents"]:
                if (resolution["quality"] == "720p" and
                    resolution["type"] == priority["type"] and
                    resolution["video_codec"] == priority["video_codec"]):
                    res720["res"] = resolution["quality"]
                    res720["url"] = resolution["url"]
                    break
        for priority in priorities:
            for resolution in movie["torrents"]:
                if (resolution["quality"] == "1080p" and
                    resolution["type"] == priority["type"] and
                    resolution["video_codec"] == priority["video_codec"]):
                    res1080["res"] = resolution["quality"]
                    res1080["url"] = resolution["url"]
                    break  
        if len(res720) == 0 and len(res1080) == 0:
            for resolution in movie["torrents"]:
                resOther["res"] = resolution["quality"]
                resOther["url"] = resolution["url"]
                break
        availableRes.append(res720)
        availableRes.append(res1080)
        availableRes.append(resOther)
        if availableRes:
            for resolution in availableRes:
                res = resolution.get('res')
                url = resolution.get('url')
                if res is not None and url is not None:
                    extra_class = "resolution_exists" if res in plex_server_resolution else "download-link resolution_available"
                    downButton += f"""<a class="resolution {extra_class}" data-filename="{title} ({year}) ({res}).torrent" data-url="{url}">{res}</a>\n"""
        # Create the movie readout HTML for each movie
        movie_readout += f"""
            <div class="movie">
                <div class="details">
                    <b class="chip rating">{rating}<i class='bx bxs-star'></i></b>
                    <b class="chip">{year}</b>
                    <b class="chip">{language}</b>
                </div>
                <a href="https://www.imdb.com/title/{imdb}" target="_blank">
                    <img src="{poster_url}" onerror="this.src='images/large-cover.jpg'" alt="{title} Poster">
                </a>
                <div class="description">
                    <h4>{title}</h4>
                </div>
                    <div class="resDownload">
                        {downButton}
                    </div>
            </div>"""
    return movie_readout

def navBar(json=None):
    movieCount =''
    movieCount = '<b  id="matches">'+str(json['data']['movie_count'])+' Matches</b>' if json != None else ""
    return open('html/navbar.html').read().format(movieCount=movieCount)

def pageButton(json, query_term):
    pages = ''
    movieCount = json['data']['movie_count']
    resultLimit = json['data']['limit']
    activePage = json['data']['page_number']
    pageLimit = math.ceil(movieCount / resultLimit)
    
    # Calculate the range of pages to display (5 pages)
    start_page = max(1, activePage - 2)
    end_page = min(pageLimit, start_page + 4)
    if end_page - start_page < 4:  # Ensure we always show 5 pages if possible
        start_page = max(1, end_page - 4)

    for number in range(start_page, end_page + 1):
        if number == activePage:
            pages += "<input type='hidden' id='activePage' data-page='" + str(number) + "'>"
            pages += "<a class='pageNumber activePage' data-page='" + str(number) + "'>" + str(number) + "</a>"
        else:
            pages += "<a class='pageNumber' data-page='" + str(number) + "'>" + str(number) + "</a>"

    if pageLimit == 1:
        return ''
    else:
        # Load your HTML template from the file 'pagebutton.html' and format it with the generated pages.
        return open('html/pagebutton.html').read().format(pages=pages, query_term=query_term, pageLimit=pageLimit)

def eztv_json():
    return 'pass'

class fetch():
    
    def imdb_data(query_term=None):
        json_data = imdb.search(query_term, tv=True) if query_term is not None else imdb.popular_movies(genre=None, sort_by=None)
        data = json.loads(json_data)
        results_data = data.get('results', [])
        return results_data
            
    def yts_movies(parameter=None, movie=None):
        movie_id = movie['id'] if movie is not None else ""
        url = f'https://yts.mx/api/v2/list_movies.json{parameter}{movie_id}'
        data = requests.get(url).json()
        if 'data' in data and data['data'].get('movie_count', 0) > 0:
            return data['data']['movies'][0] if movie is not None else data["data"]["movies"]
        else:
            return None
        
    def plex_data():
        url = f'http://10.0.0.105:32400/library/sections/1/all'
        response = requests.get(url)
        if response.status_code == 200:
            plex_xml_data = response.text
            root = ET.fromstring(plex_xml_data)
            movies = []
            for video_elem in root.findall('.//Video'):
                video_keys = {}
                media_keys = {}
                for key, value in video_elem.items():
                    video_keys[key] = value
                media_element = video_elem.find(".//Media")
                if media_element is not None:
                    media_attributes = media_element.attrib
                    for key, value in media_attributes.items():
                        media_keys[key] = value
                movie_info = {
                    'video': video_keys,
                    'media': media_keys
                }
                movies.append(movie_info)
            movie_dict = {'movies': movies}
            json_data = json.dumps(movie_dict, indent=2)
            with open('/mnt/moviehub/plex_movies.json', 'w') as json_file:
                json_file.write(json_data)
        else:
            print(f'Error: {response.status_code}')
    

class background():
    
    def update_top_movies():
        while True:
            global top_movies  # Access the global variable
            # Your code to fetch and update the top 18 movies
            new_top_movies = []
            for movie in fetch.imdb_data():
                if len(new_top_movies) >= 12:
                    break
                movie_data = fetch.yts_movies('?query_term=', movie)
                if movie_data is not None:
                    new_top_movies.append(movie_data)
            top_movies = new_top_movies  # Update the global variable
            
            global recent_movies
            recent_movies = fetch.yts_movies('?sort_by=date_added&limit=18')

            fetch.plex_data()
            time.sleep(3600)

background_thread = threading.Thread(target=background.update_top_movies)
background_thread.daemon = True  # Set the thread as a daemon to exit when the main program exits
background_thread.start()

class MovieApp:
    @cherrypy.expose
    def index(self):
        latestMoviesTiles = createMoviePoster(top_movies)
        recentMoviesTiles = createMoviePoster(recent_movies)
        return open('html/index.html').read().format(latestMoviesTiles=latestMoviesTiles,recentMoviesTiles=recentMoviesTiles,navBar=navBar())

    @cherrypy.expose
    def movie(self, query_term='', page='1', genre=None, minimum_rating=None):
        api_url = f"https://yts.mx/api/v2/list_movies.json?limit=30&query_term={query_term}&page={page}"
        api_url += f"&genre={genre}" if genre is not None else ""
        api_url += f"&minimum_rating={minimum_rating}" if minimum_rating is not None else ""
        response = requests.get(api_url)
        if response.status_code == 200 and response.json()['status_message'] == "Query was successful" and response.json()['data']['movie_count'] > 0:
            movie_tiles = createMoviePoster(response.json()["data"]["movies"])
            pageBar = pageButton(response.json(), query_term)
        else:
            movie_tiles = "<h1>No matches found<h1>"
            pageBar = ""
        return open('html/movie.html').read().format(movie_tiles=movie_tiles,navBar=navBar(response.json()),pageButton=pageBar)

    @cherrypy.expose
    def tv(self, query_term=''):
        poster_x, poster_y = '500', '750'
        results_data = fetch.imdb_data(query_term)
        html = ''
        regex_pattern = r'_V1_QL\d+_([A-Z]+)(\d+)_CR(\d+),(\d+),(\d+),(\d+)_'
        for result in results_data:
            extract = re.search(regex_pattern, result['poster'])
            item_id = result.get('id', '').replace('tt', '')
            zoom = int(extract.group(4))
            move_x = int(extract.group(3)) if extract else 0
            move_x = move_x * 9 if move_x != 0 else move_x + 6.5
            upscale_num = '510' if extract.group(2) == extract.group(5) else poster_y
            resolution = f"""_V1_QL100_{extract.group(1)}{upscale_num}_CR{str(move_x)},{str(zoom)},{poster_x},{poster_y}_"""
            poster_url = re.sub(r'_V1[\w_,]+', resolution, result['poster'])
            title = result['name']
            html += f"""<img style="width: 200px;" src="{poster_url}" id='{item_id}' onerror="this.src='images/large-cover.jpg'" alt="{title} Poster">"""
        return html
    
    @cherrypy.expose
    def download(self, url, filename):
        save_path = os.path.join('/mnt/data/deluge/watch/movies', filename)
        title = filename.replace('.torrent','')
        response = requests.get(url)
        if response.status_code == 200:
            with open(save_path, 'wb') as file:
                file.write(response.content)
            return(f"Download has been set for '{title}'.")
        else:
            print(f"Failed to download the file from '{url}'.")
            return(f"Failed to send download request. Contact your system administrator.")
    
    @cherrypy.expose
    def anime(self):
        rss = open('/mnt/deluge/config/yarss2.conf').read()
        config = {}  # Create an empty dictionary to store configuration

        with open('/mnt/deluge/config/yarss2.conf', 'r') as file:
            lines = file.readlines()

        current_section = None
        for line in lines:
            line = line.strip()
            if line.startswith("{"):
                current_section = {}
            elif line.startswith("}"):
                if current_section:
                    config.update(current_section)
                current_section = None
            elif current_section:
                key, value = line.split(":")
                current_section[key.strip()] = value.strip()

        # The 'config' dictionary now contains your configuration data
        print(config)
        return config

    @cherrypy.expose
    def downloader(self):
        return open('html/ydl.html').read().format(navBar=navBar())
    
    @cherrypy.expose
    def dropout(self):
        return open('html/dropout.html').read().format(navBar=navBar())
    
    @cherrypy.expose
    def dropoutDownloader(self,show,season,episode=None):
        download.dropout(show,season,episode)

    @cherrypy.expose
    def ydl(self, url, location):
        dl_ops = {'paths': {'temp': '/mnt/data/downloader/temp', 'home': location}, 'outtmpl': '%(uploader)s/%(title)s.%(ext)s'}
        if location == "/mnt/plex/music/podcast":
            dl_ops['format'] = 'bestaudio/best[ext=mp3]'
            dl_ops['postprocessors'] = [{
                'key': 'FFmpegExtractAudio',
                'preferredcodec': 'mp3',
                'preferredquality': '192',
            }, {
                'key': 'FFmpegMetadata',
                'add_metadata': True,
            }]
        elif location == "/mnt/plex/music/asmr":
            dl_ops['format'] = 'bestaudio/best[ext=mp3]'
            dl_ops['postprocessors'] = [{
                'key': 'FFmpegExtractAudio',
                'preferredcodec': 'mp3',
                'preferredquality': '192',
            }, {
                'key': 'FFmpegMetadata',
                'add_metadata': True,
            }]
        else:
            dl_ops['format'] = 'bestvideo[ext=mp4]+bestaudio[ext=m4a]/best'

        with yt_dlp.YoutubeDL(dl_ops) as ydl:
            ydl.download(url)
            
            # Extracting video information
            video_info = ydl.extract_info(url, download=False)
            thumbnail_url = video_info.get('thumbnail')
            
            # Download the thumbnail image
            if thumbnail_url:
                try:
                    thumbnail_filename = os.path.join(location, f"{video_info['id']}.jpg")  
                    with open(thumbnail_filename, 'wb') as thumbnail_file:
                        thumbnail_file.write(requests.get(thumbnail_url).content)
                    print("Downloaded MP4 and downloaded thumbnail successfully!")
                except Exception as e:
                    print(f"Error downloading thumbnail: {str(e)}")
            else:
                print("Downloaded MP4 but no thumbnail found.")
    
    @cherrypy.expose
    def plex(self):
        fetch.plex_data()

    @cherrypy.expose
    def yts(self):
        background.update_top_movies()

    @cherrypy.expose
    def imdb(self):
        return fetch.imdb_data()

        
cherrypy.config.update({
    'tools.staticdir.on': True,
    'tools.staticdir.dir': os.getcwd(),
    'server.socket_host': '0.0.0.0',
    'server.socket_port': 8008,
    'favicon.ico': 'favicon.ico',
})
if __name__ == '__main__':
    cherrypy.quickstart(MovieApp())
