# -*- coding: utf-8 -*-

import sys
import xbmcgui
from xbmctorrent import plugin
from xbmctorrent.scrapers import scraper
from xbmctorrent.caching import cached_route, CACHE_DIR
from xbmctorrent.utils import ensure_fanart

BASE_URL = "https://www.lostfilm.tv/"
STATIC_URL = "https://static.lostfilm.tv/"
AJAX_URL = BASE_URL + "ajaxik.php"

HEADERS = {
    'Referer': BASE_URL,
    'Accept': 'text/html, application/xml, application/xhtml+xml, image/png, image/jpeg, image/gif, image/x-xbitmap, */*',
    'Accept-Language': 'ru-RU,ru;q=0.9,en;q=0.8',
    'Accept-Encoding': 'identity, *;q=0'
}
# BANNED = [145, 157, 161, 202]

# Cache TTLs
DEFAULT_TTL = 300  # 5 minutes

_cookiejar = None
_db_connect = None


def url_get(url, params={}, headers=None, post=None):
    global _cookiejar
    import xbmcvfs
    import urllib2
    from xbmctorrent.utils import url_get as url_get_origin

    if not _cookiejar:
        import os
        import cookielib

        sid_file = os.path.join(CACHE_DIR, 'LostFilm2.cookies.dat')
        _cookiejar = cookielib.MozillaCookieJar(sid_file)

        if not xbmcvfs.exists(sid_file):
            _cookiejar.save()

        _cookiejar.load()

    cookie_handler = urllib2.HTTPCookieProcessor(_cookiejar)

    if headers is None:
        headers = HEADERS

    result = url_get_origin(url, params, headers, post, handlers=[cookie_handler])
    _cookiejar.save()

    return result


@scraper("LostFilm.tv", "http://www.lostfilm.tv/Tmpl/LostFilm/img/logo.gif", plugin.get_setting("lostfilm_enabled", bool))
@plugin.route("/lostfilm/index/<page>", options={"page": "1"})
@cached_route(ttl=DEFAULT_TTL, content_type="tvshows")
@ensure_fanart
def lostfilm_index(page=""):

    from bs4 import BeautifulSoup
    from contextlib import closing
    from xbmcswift2 import actions
    from xbmctorrent.utils import SafeDialogProgress

    with closing(SafeDialogProgress(delay_close=0)) as dialog:
        dialog.create(plugin.name)
        dialog.update(percent=0, line1="Получение информации ...", line2="", line3="")

        try:
            html_data = url_get(BASE_URL + "new/page_" + page)
            soup = BeautifulSoup(html_data, "html5lib")
            div_body = soup.select("div.serials-list")
            episodes = div_body[0].find_all("div", class_="row")
        except Exception:
            plugin.log.error("Unexpected error: %s" % sys.exc_info()[0])
            xbmcgui.Dialog().ok(plugin.name, "Не удалось получить данные от сервера.")
            return

        yield {
            "label": "[COLOR FF00FF00][Полный список сериалов][/COLOR]",
            "path": plugin.url_for("lostfilm_all", page=0),
        }

        done = 0
        for episode in episodes:
            episode_name_ru = episode.find("div", class_="alpha").text
            episode_name_en = episode.find("div", class_="beta").text

            data_code = episode.find("div", class_="haveseen-btn")["data-code"]
            tvshowid, season, episode_num = data_code.split("-")

            show = {
                "title": episode.find("div", class_="name-ru").text,
                "title_orig": episode.find("div", class_="name-en").text,
                "alias": episode.find("a")["href"].split("/")[2],
                "id": tvshowid
            }

            if dialog.iscanceled():
                return

            item = _lostfilm_updateitem_from_db({
                "label": "[COLOR FFFFFFCC][%02d.%02d][/COLOR] [COLOR FFFFFFFF][B]%s[/B][/COLOR]: %s" % (int(season), int(episode_num), show["title"], episode_name_ru),
                "path": plugin.url_for("lostfilm_play", showid=tvshowid, season=season, episode=episode_num),
                "is_playable": True,
                "info": {
                    "title": "%s [%s]" % (episode_name_ru, episode_name_en),
                    "season": season,
                    "episode": episode_num
                },
                "context_menu": [
                    ("Все серии", actions.update_view(plugin.url_for("lostfilm_tvshow", alias=show["alias"])))
                ]
            }, show)

            if int(season) == 999:
                item.update({
                    "label": "[COLOR FFFFFFCC][xx.%02d][/COLOR] [COLOR FFFFFFFF][B]%s[/B][/COLOR]: %s" % (int(episode_num), show["title"], episode_name_ru),
                })
            elif "-" not in episode_num and int(episode_num) == 999:
                item.update({
                    "label": "[COLOR FFFFFFCC][%02d.xx][/COLOR] [COLOR FFFFFFFF][B]%s[/B][/COLOR]: %s" % (int(season), show["title"], episode_name_ru),
                    "is_playable": False
                })
                item.setdefault("info", {}).update({
                    "episode": "all"
                })

            done += 1
            dialog.update(
                percent=int(done * 100.0 / len(episodes)),
                line2=item.get("info", {}).get("tvshowtitle", "") or item.get("info", {}).get("title", "") or item["label"],
                line3=""
            )

            yield item

        if len(episodes) >= 10:
            yield {
                "label": "[COLOR FF00FF00][Далее >][/COLOR]",
                "path": plugin.url_for("lostfilm_index", page=(int(page) + 1)),
            }

        _lostfilm_close_dbase()


@plugin.route("/lostfilm/all/<page>")
@cached_route(ttl=DEFAULT_TTL, content_type="tvshows")
@ensure_fanart
def lostfilm_all(page):
    from json import loads
    from contextlib import closing
    from xbmctorrent.utils import SafeDialogProgress

    page = int(page)
    with closing(SafeDialogProgress(delay_close=0)) as dialog:
        dialog.create(plugin.name)
        dialog.update(percent=0, line1=u"Получение информации ...", line2="", line3="")

        params = {"act": "serial", "type": "search", "o": page * 30, "t": 0, "s": 2}

        data = []
        tvshows = []
        try:
            while True:
                json_data = url_get(AJAX_URL, params=params)
                data = loads(json_data).get("data", [])
                tvshows += data
                if len(data) < 10 or len(tvshows) >= 30:
                    break
                params["o"] += len(data)
        except Exception:
            plugin.log.error("Unexpected error: %s" % sys.exc_info()[0])
            xbmcgui.Dialog().ok(plugin.name, u"Не удалось получить данные от сервера")
            return

        done = 0
        for tvshow in tvshows:
            if dialog.iscanceled():
                return

            item = _lostfilm_updateitem_from_db({
                "label": "[COLOR FFFFFFFF][B]%s[/B][/COLOR] [%s]" % (tvshow["title"], tvshow["title_orig"]),
                "path": plugin.url_for("lostfilm_tvshow", alias=tvshow["alias"]),
                "is_playable": False,
                "info": {
                    "title": "%s [%s]" % (tvshow["title"], tvshow["title_orig"])
                }
            }, tvshow)

            done += 1
            dialog.update(
                percent=int(done * 100.0 / len(tvshows)),
                line2=item.get("info", {}).get("tvshowtitle", "") or item.get("info", {}).get("title", "") or item["label"],
                line3=""
            )

            yield item

        _lostfilm_close_dbase()

        if len(data) == 10:
            yield {
                "label": "[COLOR FF00FF00][Далее >][/COLOR]",
                "path": plugin.url_for("lostfilm_all", page=page + 1),
            }


@plugin.route("/lostfilm/show/<alias>")
@cached_route(ttl=DEFAULT_TTL, content_type="episodes")
@ensure_fanart
def lostfilm_tvshow(alias):
    import re
    from bs4 import BeautifulSoup
    from contextlib import closing
    from xbmctorrent.utils import SafeDialogProgress

    with closing(SafeDialogProgress(delay_close=0)) as dialog:
        dialog.create(plugin.name)
        dialog.update(percent=0, line1="Получение информации ...", line2="", line3="")

        try:
            html_data = url_get(BASE_URL + "series/%s/seasons" % alias)
            soup = BeautifulSoup(html_data, "html5lib", from_encoding="utf-8")
            serie_blocks = soup.find_all("div", "serie-block")
        except Exception:
            import xbmcgui
            plugin.log.error("Unexpected error: %s" % sys.exc_info()[0])
            xbmcgui.Dialog().ok(plugin.name, "Не удалось получить данные от сервера")
            return

        fav_btn = str(soup.find_all("div", re.compile("favorites-btn2?")))
        showid = int(fav_btn[fav_btn.find("(") + 1:fav_btn.find(")")])
        show = {
            "title": soup.find("div", "title-ru").text,
            "title_orig": soup.find("div", "title-en").text,
            "alias": alias,
            "id": fav_btn[fav_btn.find("(") + 1:fav_btn.find(")")]
        }
        show_info = _lostfilm_get_db_info(show)
        _lostfilm_close_dbase()

        done = 0
        for block in serie_blocks:
            season_details = block.find("div", class_="movie-details-block")
            series_table = block.find("table", id=re.compile("season_series_(\d+)"))

            if season_details:
                play_btn = season_details.find("div", re.compile("external-btn2?")).get("onclick", None)
                if play_btn:  # if btn has onclick attr then a season is completed and can be played
                    episode_name = u"%s полностью" % block.find("h2").text
                    seen_btn = season_details.find("div", "haveseen-btn")["data-code"]
                    season_num = seen_btn.split("-")[-1]
                    episode_num = "999"

                    yield _lostfilm_updateitem_from_info({
                        "label": "[COLOR FFFFFFCC][%02d.xx][/COLOR] [COLOR FF00FF00][B]%s[/B][/COLOR]" % (int(season_num), episode_name),
                        "path": plugin.url_for("lostfilm_play", showid=showid, season=season_num, episode=episode_num),
                        "is_playable": False,
                        "info": {
                            "title": episode_name,
                            "season": season_num,
                            "episode": "all"
                        }
                    }, show_info)

            if series_table:
                if "999999" in series_table["id"]:
                    from xbmcswift2 import actions
                    yield _lostfilm_updateitem_from_info({
                        "label": "[COLOR FFFFFFCC][xx.xx][/COLOR] [COLOR FF00FF00][B]%s[/B][/COLOR]" % (block.find("h2").text),
                        "is_playable": False,
                        "path": actions.background(plugin.url_for("index")),  # fake action
                        "info": {
                            "title": block.find("h2").text,
                            "season": "1",
                            "episode": "all"
                        }
                    }, show_info)

                for serie in series_table.find_all("tr"):
                    episode = serie.find("td", "gamma")
                    episode_details = episode.find("div")
                    if not episode_details:
                        continue

                    title_en = episode_details.find("span")
                    title_ru = episode_details.contents[0].strip()

                    seen_btn = serie.find("div", "haveseen-btn")["data-code"]
                    _, season_num, episode_num = seen_btn.split("-")

                    item = {
                        "label": "[COLOR FFFFFFCC][%02d.%02d][/COLOR] [COLOR FFFFFFFF][B]%s[/B][/COLOR] [%s]" % (
                            int(season_num), int(episode_num), title_ru, title_en and title_en.text or ""),
                        "path": plugin.url_for("lostfilm_play", showid=showid, season=season_num, episode=episode_num),
                        "is_playable": True,
                        "info": {
                            "title": "%s [%s]" % (title_ru, title_en and title_en.text or ""),
                            "season": season_num,
                            "episode": episode_num
                        }
                    }
                    if int(season_num) == 999:
                        item.update({
                            "label": "[COLOR FFFFFFCC][xx.%02d][/COLOR] [COLOR FFFFFFFF][B]%s[/B][/COLOR] [%s]" % (
                                int(episode_num), title_ru, title_en and title_en.text or "")
                        })
                        item.setdefault("info", {}).update({
                            "season": 1
                        })

                    item = _lostfilm_updateitem_from_info(item, show_info)

                    done += 1
                    dialog.update(
                        percent=int(done * 100.0 / len(serie_blocks)),
                        line2=item.get("info", {}).get("tvshowtitle", "") or item.get("info", {}).get("title", "") or item["label"],
                        line3=""
                    )

                    yield item


@plugin.route("/lostfilm/play/<showid>/<season>/<episode>")
@cached_route(ttl=DEFAULT_TTL, content_type="episodes")
@ensure_fanart
def lostfilm_play(showid, season, episode):
    import re
    from contextlib import closing
    from bs4 import BeautifulSoup
    from xbmctorrent.acestream import ace_supported
    from xbmctorrent.utils import SafeDialogProgress, get_quality_from_name

    with closing(SafeDialogProgress(delay_close=0)) as dialog:
        dialog.create(plugin.name)
        dialog.update(percent=0, line1="Получение информации о релизе...", line2="", line3="")

        params = {"c": showid, "s": season, "e": episode}

        try:
            search_url = BASE_URL + "v_search.php"
            html = url_get(search_url, params=params)
            # catch 'log in first' then login
            if html.find("log in first") >= 0:
                dialog.update(percent=10, line2="Требуется авторизация. Авторизация...")
                if not plugin.get_setting("lostfilm_login") and not plugin.get_setting("lostfilm_passwd"):
                    plugin.notify("Проверьте настройки авторизации.", delay=15000)
                    return

                if not _lostfilm_login():
                    xbmcgui.Dialog().ok(plugin.name, "Авторизация неудалась1. Проверьте настройки.")
                    return

                dialog.update(percent=30, line2="Загрузка.", line3="")
                html = url_get(search_url, params=params)

                if html.find("log in first") >= 0:
                    xbmcgui.Dialog().ok(plugin.name, "Авторизация неудалась2. Проверьте настройки.")
                    return
        except Exception:
            plugin.log.error("Unexpected error: %s" % sys.exc_info()[0])
            xbmcgui.Dialog().ok(plugin.name, "Не удалось получить данные от сервера")
            return

        # catch redirect
        if html.find("location.replace") >= 0:
            replace_url = html[html.find("(\"") + 2:html.find("\");")]
            html = url_get(replace_url)

        dialog.update(percent=50, line2="Обработка данных.")
        soup = BeautifulSoup(html, "html5lib")
        divs = soup.find_all("div", class_=re.compile("main"))

        releases = [d.find("a") for d in divs]
        quality = plugin.get_setting("lostfilm_qlt", int) or 0

        if quality <= 0 or quality > len(releases):
            select_items = []
            for release in releases:
                lines = release.text.split("\n")
                select_items.append(lines[-1])

            select = xbmcgui.Dialog().select("Выберите желаемое качество", select_items)
        else:
            select = quality - 1

        if select >= 0:
            selected = releases[select]
            torrent_url = selected["href"]

            if (("-" not in episode and int(episode) == 999) or ("." in season and "-" in episode)):
                if "." in season:
                    season = season[:season.find(u".")]

                plugin.add_sort_method("label")

                show_info = _lostfilm_get_db_info_by_id(showid)
                _lostfilm_close_dbase()

                try:
                    from bencode import bdecode
                    torrent_data = url_get(torrent_url)
                    metadata = bdecode(torrent_data)
                except Exception:
                    plugin.log.error("Cannot get data from remote server")
                    xbmcgui.Dialog().ok(plugin.name, "Не удалось получить данные от сервера")
                    return

                e = re.compile("(e[\d]+)?e([\d]+)\.", re.I | re.S | re.U)
                for index, item in enumerate(metadata["info"]["files"]):
                    file_name = " / ".join(item["path"])
                    r = e.search(file_name)
                    if r:
                        if r.group(1):
                            episode = r.group(1)[1:]
                        else:
                            episode = r.group(2)
                    else:
                        episode = u""

                    if plugin.get_setting("torrent_engine", int) == 1 and ace_supported():
                        path = plugin.url_for("torrent_play", url=torrent_url, index=index, name=file_name)
                    else:
                        path = plugin.url_for("play_file", uri=torrent_url, index=index)

                    yield _lostfilm_updateitem_from_info({
                        "label": file_name,
                        "path": path,
                        "is_playable": True,
                        "info": {
                            "title": file_name,
                            "season": season,
                            "episode": episode
                        },
                        "stream_info": get_quality_from_name(file_name)
                    }, show_info)
            else:
                if plugin.get_setting("torrent_engine", int) == 1 and ace_supported():
                    path = plugin.url_for("torrent_play", url=torrent_url, index=0, name="LostFilm.Tv")
                else:
                    path = plugin.url_for("play", uri=torrent_url)
                plugin.redirect(path)


def _lostfilm_login():
    from json import loads

    values = {
        "act": "users",
        "type": "login",
        "mail": plugin.get_setting("lostfilm_login"),
        "pass": plugin.get_setting("lostfilm_passw"),
        "rem": 1,
    }

    jsn = url_get(AJAX_URL, post=values)
    result = loads(jsn)

    return result.get("result", "") == "ok" and result.get("success", False)


def _lostfilm_updateitem_from_db(item, show):
    return _lostfilm_updateitem_from_info(item, _lostfilm_get_db_info(show))


def _lostfilm_updateitem_from_info(item, result={}):
    if result:
        base_url = STATIC_URL + "Images/%s/Posters/" % result["id"]
        info = item.setdefault("info", {})
        fanart_img = base_url + "poster.jpg"
        poster_url = base_url + "shmoster_s%s.jpg" % item["info"].get("season", "1")

        result.update({"cover": poster_url})
        item.update({
            "icon": poster_url,
            "thumbnail": poster_url,
            "poster": poster_url
        })
        info.update(result)
        item.setdefault("properties", {}).update({
            "fanart_image": fanart_img
        })

    return item


def _lostfilm_get_meta(show_info):
    import re
    from bs4 import BeautifulSoup

    try:
        html = url_get(BASE_URL + "series/%s/" % show_info["alias"])
    except Exception:
        plugin.log.info("Cannot get data from lostfilm")
        return None

    if not html:
        plugin.log.info("Cannot get data from lostfilm")
        return None

    soup = BeautifulSoup(html, "html5lib", from_encoding="utf-8")
    content = soup.select("div.left-pane")[0]

    title_ru = content.find("div", "title-ru")
    title_en = content.find("div", "title-en")
    info = {
        "id": show_info["id"],
        "alias": show_info["alias"],
        "tvshowtitle": title_ru.text.strip(),
        "original_title": (title_en and title_en.text or title_ru.text).strip()
    }

    description = content.find("div", "text-block description")
    if description:
        desc_body = description.find("div", {"class": "body", "style": re.compile('(.+)')})
        match = re.compile('<strong class="bb">[^<]+?</strong><br/>(.*?)</div>', re.U | re.S).search(unicode(desc_body))
        info["plot"] = (match and BeautifulSoup(match.group(1)).text or desc_body.text).replace("\n", "[CR]")

    details = content.find("div", "details-pane")
    if details:
        lines = [BeautifulSoup(line).text.strip() for div in details.findAll("div") for line in unicode(div).split("<br/>")]
        for line in [line for line in lines if line.strip()]:
            if u"Страна:" in line:
                _, value = line.split(u":")
                value = value.strip()
                info["country"] = value[value.find("(") + 1:value.find(")")]
                info["studio"] = value[:value.find("(") - 1].strip()
            elif u"Премьера:" in line:
                _, value = line.split(u":")
                info["year"] = value.strip()[-4:]
            elif u"Жанр:" in line:
                _, value = line.split(u":")
                info["genre"] = " / ".join([g.strip() for g in value.split(",") if g.strip()])
            elif u"IMDb:" in line:
                _, value = line.split(u":")
                info["rating"] = value.strip()
    return info


def _lostfilm_get_db_info_by_id(showid):
    connection = _lostfilm_dbase()
    cursor = connection.cursor()
    cursor.execute("SELECT alias FROM aliases WHERE id = '%s';" % showid)
    row = cursor.fetchone()
    cursor.close()
    return row and _lostfilm_get_db_info({"id": showid, "alias": row[0]}) or {}


def _lostfilm_get_db_info(show_info):
    from pickle import loads, dumps
    from sqlite3 import Binary

    connection = _lostfilm_dbase()
    try:
        cursor = connection.cursor()
        cursor.execute("SELECT data FROM meta WHERE id = '%s';" % show_info["id"])
        row = cursor.fetchone()
        cursor.close()

        if row:
            try:
                obj = loads(row[0])
            except Exception:
                pass
            else:
                return obj

        result = _lostfilm_get_meta(show_info)

        if result:
            cursor = connection.cursor()
            cursor.execute('replace into aliases(id,alias) values(?,?)', (show_info["id"], show_info["alias"]))
            cursor.execute('replace into meta(id,data) values(?,?)', (show_info["id"], Binary(dumps(result))))
            connection.commit()
            cursor.close()
            return result

    except Exception:
        plugin.log.error("unexpected error: %s" % sys.exc_info()[0])
        return show_info

    return show_info


def _lostfilm_dbase():
    global _db_connect
    if not _db_connect:
        import os
        import sqlite3
        import xbmcvfs

        db_name = os.path.join(CACHE_DIR, "lostfilm2.db")
        first = False
        if not xbmcvfs.exists(db_name):
            first = True

        _db_connect = sqlite3.connect(database=db_name)

        if first:
            cursor = _db_connect.cursor()
            cursor.execute('pragma auto_vacuum=1')
            cursor.execute('create table meta(id varchar(20) unique, data blob)')
            cursor.execute('create table aliases(id varchar(20) unique, alias varchar(128) unique)')
            _db_connect.commit()
            cursor.close()

    return _db_connect


def _lostfilm_close_dbase():
    global _db_connect
    if _db_connect:
        _db_connect.close()
        _db_connect = None
