"""
Search the audio on YT
"""
import asyncio
import logging
import requests
import json
from homeassistant.components import ais_cloud
from homeassistant.components import ais_updater
from homeassistant.components.ais_dom import ais_global

aisCloud = ais_cloud.AisCloudWS()
URL_BASE = "https://www.googleapis.com/youtube/v3/search"
DEFAULT_ACTION = "No video"

DOMAIN = "ais_yt_service"
SERVICE_SEARCH = "search"
ATTR_QUERY = "query"
ATTR_NAME = "name"

G_YT_KEY = None
_LOGGER = logging.getLogger(__name__)


@asyncio.coroutine
def async_setup(hass, config):
    """Register the service."""
    config = config.get(DOMAIN, {})
    data = hass.data[DOMAIN] = YouTubeData(hass)
    yield from data.get_key_async()

    @asyncio.coroutine
    def search(service):
        """search service about audio"""
        _LOGGER.debug("search")
        yield from data.process_search_async(service)

    # @asyncio.coroutine
    def select_track_uri(service):
        """select track uri"""
        _LOGGER.debug("select_track_uri")
        data.process_select_track_uri(service)

    # register services
    hass.services.async_register(DOMAIN, SERVICE_SEARCH, search)
    hass.services.async_register(DOMAIN, "select_track_uri", select_track_uri)

    return True


class YouTubeData:
    """Class to hold YT data."""

    def __init__(self, hass):
        """Initialize the radio stations."""
        self.hass = hass

    @asyncio.coroutine
    def get_key_async(self):
        def load():
            global G_YT_KEY
            try:
                ws_resp = aisCloud.key("ytsearch")
                json_ws_resp = ws_resp.json()
                G_YT_KEY = json_ws_resp["key"]
            except:
                ais_global.G_OFFLINE_MODE = True

        yield from self.hass.async_add_job(load)

    @asyncio.coroutine
    def get_new_key(self, old_key, query, prev_page_token, next_page_token):
        global G_YT_KEY
        try:
            ws_resp = aisCloud.new_key("ytsearch", old_key)
            json_ws_resp = ws_resp.json()
            G_YT_KEY = json_ws_resp["key"]
        except Exception as e:
            _LOGGER.error("YouTube " + str(e))

        # check if new key is new (different from old one)
        if G_YT_KEY != old_key:
            # call the service again
            yield from self.hass.services.async_call(
                "ais_yt_service",
                "search",
                {
                    ATTR_QUERY: query,
                    "prevPageToken": prev_page_token,
                    "nextPageToken": next_page_token,
                },
            )

    @asyncio.coroutine
    def process_search_async(self, call):
        """Search in service."""
        global G_YT_KEY
        query = None
        prev_page_token = None
        next_page_token = None
        text = None
        if ATTR_QUERY in call.data:
            query = call.data[ATTR_QUERY]

        if "prevPageToken" in call.data:
            if call.data["prevPageToken"] is not None:
                prev_page_token = call.data["prevPageToken"].replace(
                    "prevPageToken_", ""
                )

        if "nextPageToken" in call.data:
            if call.data["nextPageToken"] is not None:
                next_page_token = call.data["nextPageToken"].replace(
                    "nextPageToken_", ""
                )

        if (
            (query is None or len(query.strip()) == 0)
            and prev_page_token is None
            and next_page_token is None
        ):
            # get tracks from favorites
            yield from self.hass.services.async_call(
                "ais_bookmarks",
                "get_favorites",
                {"audio_source": ais_global.G_AN_MUSIC},
            )
            return

        if G_YT_KEY is None:
            try:
                ws_resp = aisCloud.key("ytsearch")
                json_ws_resp = ws_resp.json()
                G_YT_KEY = json_ws_resp["key"]
            except Exception as e:
                ais_global.G_OFFLINE_MODE = True
                yield from self.hass.services.async_call(
                    "ais_ai_service",
                    "say_it",
                    {"text": "Brak odpowiedzi, sprawdź połączenie z Intenetem"},
                )
                _LOGGER.error("process_search_async " + str(e))
                return

        params = dict(
            order="relevance",
            part="snippet",
            key=G_YT_KEY,
            maxResults=10,
            type="video",
            fields="items/id/videoId, items/snippet/title, items/snippet/thumbnails/medium/url, "
            "pageInfo/totalResults, nextPageToken, prevPageToken",
        )
        params.update({"q": query})
        if prev_page_token is not None:
            params.update({"pageToken": prev_page_token})
        if next_page_token is not None:
            params.update({"pageToken": next_page_token})
        data = requests.get(URL_BASE, params=params).json()

        # check if error
        if "error" in data:
            for error in data["error"]["errors"]:
                if error["reason"] == "quotaExceeded":
                    # get the new token and try again
                    yield from self.get_new_key(
                        G_YT_KEY, query, prev_page_token, next_page_token
                    )
                    return

                if text is None:
                    text = error["message"]
                else:
                    text = text + " " + error["message"]
            yield from self.hass.services.async_call(
                "ais_ai_service", "say_it", {"text": text}
            )
            return

        list_info = {}
        list_idx = 0

        total_results = 0
        if "pageInfo" in data:
            total_results = data["pageInfo"]["totalResults"]

        if "prevPageToken" in data:
            list_info[list_idx] = {}
            list_info[list_idx][
                "title"
            ] = "pobierz poprzednią stronę wyników wyszukiwania"
            list_info[list_idx][
                "name"
            ] = "pobierz poprzednią stronę wyników wyszukiwania"
            list_info[list_idx]["thumbnail"] = "/static/icons/favicon-100x100.png"
            list_info[list_idx]["uri"] = "prevPageToken_" + data["prevPageToken"]
            list_info[list_idx]["media_source"] = ais_global.G_AN_MUSIC
            list_info[list_idx]["audio_type"] = ais_global.G_AN_MUSIC
            list_info[list_idx]["icon"] = "mdi:page-previous"
            list_info[list_idx]["query"] = query
            list_idx = list_idx + 1

        if "items" in data:
            for item in data["items"]:
                list_info[list_idx] = {}
                list_info[list_idx]["title"] = item["snippet"]["title"]
                list_info[list_idx]["name"] = item["snippet"]["title"]
                # item['snippet']['description']
                list_info[list_idx]["thumbnail"] = item["snippet"]["thumbnails"][
                    "medium"
                ]["url"]
                list_info[list_idx]["uri"] = item["id"]["videoId"]
                list_info[list_idx]["media_source"] = ais_global.G_AN_MUSIC
                list_info[list_idx]["audio_type"] = ais_global.G_AN_MUSIC
                list_info[list_idx]["icon"] = "mdi:play"
                list_idx = list_idx + 1

        if "nextPageToken" in data:
            list_info[list_idx] = {}
            list_info[list_idx][
                "title"
            ] = "pobierz następną stronę wyników wyszukiwania"
            list_info[list_idx]["name"] = "pobierz następną stronę wyników wyszukiwania"
            list_info[list_idx]["thumbnail"] = "/static/icons/favicon-100x100.png"
            list_info[list_idx]["uri"] = "nextPageToken_" + data["nextPageToken"]
            list_info[list_idx]["media_source"] = ais_global.G_AN_MUSIC
            list_info[list_idx]["audio_type"] = ais_global.G_AN_MUSIC
            list_info[list_idx]["icon"] = "mdi:page-next"
            list_info[list_idx]["query"] = query

        # update list
        self.hass.states.async_set("sensor.youtubelist", -1, list_info)
        if len(list_info) > 0:
            # from remote
            import homeassistant.components.ais_ai_service as ais_ai

            if (
                ais_ai.CURR_ENTITIE == "input_text.ais_music_query"
                and ais_ai.CURR_BUTTON_CODE == 4
            ):
                ais_ai.set_curr_entity(self.hass, "sensor.youtubelist")
                ais_ai.CURR_ENTITIE_ENTERED = True
                text = "Znaleziono: %s, wybierz pozycję którą mam włączyć" % (
                    str(total_results)
                )
            else:
                if next_page_token is None and prev_page_token is None:
                    text = "Znaleziono: %s, włączam pierwszy: %s" % (
                        str(total_results),
                        list_info[0]["title"],
                    )
                    yield from self.hass.services.async_call(
                        "ais_yt_service", "select_track_uri", {"id": 0}
                    )

                if ais_ai.CURR_ENTITIE == "media_player.wbudowany_glosnik":
                    if next_page_token is not None and ais_ai.CURR_BUTTON_CODE == 22:
                        text = (
                            "Pobrano następną stronę wyników, włączam pierwszy: %s"
                            % (list_info[1]["title"])
                        )
                        yield from self.hass.services.async_call(
                            "ais_yt_service", "select_track_uri", {"id": 1}
                        )
                    elif prev_page_token is not None and ais_ai.CURR_BUTTON_CODE == 21:
                        text = (
                            "Pobrano poprzednią stronę wyników, włączam ostatni: %s"
                            % (list_info[len(list_info) - 2]["title"])
                        )
                        yield from self.hass.services.async_call(
                            "ais_yt_service",
                            "select_track_uri",
                            {"id": len(list_info) - 2},
                        )

        else:
            text = "Brak wnyników na YouTube dla zapytania %s" % query
        # info to user
        if text is not None:
            yield from self.hass.services.async_call(
                "ais_ai_service", "say_it", {"text": text}
            )

    def process_select_track_uri(self, call):
        _LOGGER.info("process_select_track_uri")
        # """play track by id on sensor list."""
        call_id = call.data["id"]
        list_sensor = "sensor.youtubelist"
        media_source = ais_global.G_AN_MUSIC
        if "media_source" in call.data:
            media_source = call.data["media_source"]
            if media_source == ais_global.G_AN_FAVORITE:
                list_sensor = "sensor.aisfavoriteslist"
            elif media_source == ais_global.G_AN_BOOKMARK:
                list_sensor = "sensor.aisbookmarkslist"

        state = self.hass.states.get(list_sensor)
        attr = state.attributes
        track = attr.get(int(call_id))
        media_position_ms = track.get("media_position_ms", 0)
        url = "https://www.youtube.com/watch?v="
        # update list
        self.hass.states.async_set(list_sensor, call_id, attr)

        # get prev / next results
        if track["uri"].startswith("prevPageToken_"):
            self.hass.services.call(
                "ais_yt_service",
                "search",
                {"prevPageToken": track["uri"], "query": track["query"]},
            )
            return
        if track["uri"].startswith("nextPageToken_"):
            self.hass.services.call(
                "ais_yt_service",
                "search",
                {"nextPageToken": track["uri"], "query": track["query"]},
            )
            return

        # try to get media url from AIS cloud
        media_url = None
        try:
            local_extractor_version = ais_updater.get_package_version("youtube_dl")
            ws_resp = aisCloud.extract_media(
                url + track["uri"], local_extractor_version
            )
            json_ws_resp = ws_resp.json()
            _LOGGER.info(str(json_ws_resp))
            #
            cloud_extractor_version = json_ws_resp["extractor_version"]
            if "youtube_dl==" + cloud_extractor_version != local_extractor_version:
                self.hass.services.call(
                    "ais_updater",
                    "upgrade_package",
                    {"package": "youtube_dl", "version": cloud_extractor_version},
                )
            media_url = json_ws_resp["url"]
        except Exception as e:
            _LOGGER.info("extract_media error: " + str(e))

        all_ok = False
        if media_url is not None and len(media_url) > 0:
            # check 403
            import requests

            try:
                r = requests.head(media_url, allow_redirects=True, timeout=1)
                if r.status_code < 400:
                    all_ok = True
            except Exception as e:
                _LOGGER.warning("Request to youtube error " + str(e))

        if all_ok:
            # set stream url, image and title
            _audio_info = json.dumps(
                {
                    "IMAGE_URL": track["thumbnail"],
                    "NAME": track["title"],
                    "lookup_url": track["uri"],
                    "MEDIA_SOURCE": media_source,
                    "media_content_id": media_url,
                    "media_position_ms": media_position_ms,
                }
            )
            self.hass.services.call(
                "media_player",
                "play_media",
                {
                    "entity_id": ais_global.G_LOCAL_EXO_PLAYER_ENTITY_ID,
                    "media_content_type": "ais_content_info",
                    "media_content_id": _audio_info,
                },
            )
        else:
            # use media_extractor to extract locally
            self.hass.services.call(
                "media_extractor",
                "play_media",
                {
                    "entity_id": ais_global.G_LOCAL_EXO_PLAYER_ENTITY_ID,
                    "media_content_id": url + track["uri"],
                    "media_content_type": "video/youtube",
                },
            )

            # set stream image and title
            _audio_info = json.dumps(
                {
                    "IMAGE_URL": track["thumbnail"],
                    "NAME": track["title"],
                    "MEDIA_SOURCE": ais_global.G_AN_MUSIC,
                    "lookup_url": track["uri"],
                }
            )
            self.hass.services.call(
                "media_player",
                "play_media",
                {
                    "entity_id": ais_global.G_LOCAL_EXO_PLAYER_ENTITY_ID,
                    "media_content_type": "ais_info",
                    "media_content_id": _audio_info,
                },
            )
