#!/usr/bin/env python

"""
Inspired form https://github.com/sydev/movie-blog-api
"""

from pyquery import PyQuery as pq
import os
import re
import json
import html
import atexit
import argparse
import requests
import xmltodict
import urllib.parse

readline_loaded = False
try:
    # In unix readline needs to be loaded so that
    # arrowkeys work in input
    import readline  # noqa: F401

    readline_loaded = True
except ImportError:
    pass


stdHeader = {
    'User-Agent': (
        'Mozilla/5.0 (X11; Linux x86_64)'
        + ' AppleWebKit/537.36 (KHTML, like Gecko)'
        + ' Chrome/78.0.3904.108 Safari/537.36'
    ),
    'Content-Type': 'application/x-www-form-urlencoded',
}

domain_response = requests.get('https://movie-blog.org')
mb_domain = domain_response.url


speed_units = ['kb/s', 'kbps', 'mb/s', 'mbps', 'Kbp', 'VIDEO', '@', 'Video', 'Größe', 'Resolution']

relevant_providers = ['zippyshare.com', 'anonfile.com', 'megaup.net']


class Movie_Blog_Entry:
    def __init__(self, title: str, link: str, speed_information: [], link_list: []):
        self.title = title
        self.link = link
        self.speed_information = speed_information
        self.link_list = link_list

    def __str__(self):

        output = ""

        output += "\n# {}".format(self.title)
        output += "\n# {}".format(self.link)
        if len(self.speed_information) > 0:
            output += "\n# {}".format(self.speed_information)

        for link in self.link_list:
            output += "\n{}".format(link)

        return output


def convert_xml_to_dict(xml: str):
    """
    Converts a xml string to a dictionary
    """
    xml_dict = xmltodict.parse(xml)
    json_str = json.dumps(xml_dict)
    converted_dict = json.loads(json_str)
    return converted_dict


def get_speed_information(html_content: str):
    speed_information = []
    html_lines = re.sub(r'<\s*br\s*(/)?>', '\n', html_content)
    html_lines = html_lines.split('\n')
    for line in html_lines:
        cleaned_line = html.unescape(line)
        cleaned_line = re.sub("<.*?>", " ", cleaned_line)
        cleaned_line = ' '.join(cleaned_line.split())
        for unit in speed_units:
            if cleaned_line.find(unit) >= 0:
                speed_information.append(cleaned_line)
                break

    return speed_information


def search(query='') -> [Movie_Blog_Entry]:
    query = urllib.parse.quote(query)
    url = '{}/?s={}&feed=rss2'.format(mb_domain, query)

    try:
        response = requests.get(url, headers=stdHeader)

        xml = response.text

        page_dict = convert_xml_to_dict(xml)

        page_rss_dict = page_dict.get('rss', {})
        page_items = page_rss_dict.get('channel', {}).get('item', [])

        if not isinstance(page_items, list):
            page_items = [page_items]
        # entries are mapped to there provider
        mapped_entries = {}

        for item in page_items:
            item_content = item.get('content:encoded', '')
            item_title = item.get('title', '')
            item_link = item.get('link', '')

            speed_information = get_speed_information(item_content)

            d = pq(item_content)
            links = d('span[id^=mirror][style] a')

            if links.length == 0:
                links = d('a')

            mapped_links = {}

            for provider in relevant_providers:
                for link in links:
                    if link.text is None:
                        continue
                    parsed_provieder = link.text.strip().lower()
                    if provider in parsed_provieder:
                        link_href = link.attrib.get('href', '')
                        if link_href != '':
                            if provider not in mapped_links:
                                mapped_links[provider] = []

                            mapped_links[provider].append(link_href)

            for provider in mapped_links:
                if provider not in mapped_entries:
                    mapped_entries[provider] = []

                new_entry = Movie_Blog_Entry(item_title, item_link, speed_information, mapped_links[provider])

                mapped_entries[provider].append(new_entry)

        return mapped_entries

    except Exception as e:
        print(e)

    return {}


def print_entries(mapped_entries: {}):

    if len(mapped_entries) == 0:
        print('No links found!')

    for provider in mapped_entries:
        entries_list = mapped_entries[provider]

        print('\n\n{}\n'.format(provider))
        for entry in entries_list:
            print(entry)


histfile = os.path.join(os.path.expanduser("~"), ".movie-blog-history")
parser = argparse.ArgumentParser(
    description=('Movie-Blog Search Engine helps to find the links on movie-block.org from different providers.')
)

parser.add_argument('query', type=str, nargs='*', help='For an instant search just enter your request as a parameter.')
parser.add_argument(
    '-p',
    '--provider',
    action='append',
    type=str,
    help="With this option you can add several individual providers to the search.",
)
parser.add_argument(
    '-c',
    '--clear-providers',
    dest='clear_providers',
    action='store_true',
    help=(
        'If you set this option the default provider list will be cleared before the specified providers'
        + ' are added to the list.'
    ),
)
args = parser.parse_args()

try:
    if readline_loaded:
        readline.read_history_file(histfile)
        readline.set_history_length(10000)  # default infinity
except FileNotFoundError:
    pass

if readline_loaded:
    atexit.register(readline.write_history_file, histfile)

if args.clear_providers is True:
    relevant_providers = []

if args.provider is not None:
    new_providers = []
    for provider in args.provider:
        new_providers.append(provider.strip().lower())
    relevant_providers += new_providers

if args.query is not None and len(args.query) > 0:
    arg_query = ' '.join(args.query)
    print_entries(search(arg_query))
    if readline_loaded:
        readline.add_history(arg_query)


try:
    while True:
        print('\n\n\n')
        print('#' * 60)
        print('\n\n\n')
        search_input = input('Search for:   ')
        print_entries(search(search_input))
except (KeyboardInterrupt, SystemExit):
    print("\n\nSee you soon :)")
