"""
$description Live and on-demand video service from World Wrestling Entertainment, Inc.
$url network.wwe.com
$type live, vod
$account Required
"""

import json
import logging
import re
from urllib.parse import parse_qsl, urlparse

from streamlink.plugin import Plugin, PluginError, pluginargument, pluginmatcher
from streamlink.plugin.api import useragents
from streamlink.stream.hls import HLSStream
from streamlink.utils.times import seconds_to_hhmmss


log = logging.getLogger(__name__)


@pluginmatcher(re.compile(
    r"https?://network\.wwe\.com/(?:video|live)/(?P<stream_id>\d+)",
))
@pluginargument(
    "email",
    required=True,
    requires=["password"],
    metavar="EMAIL",
    help="The email associated with your WWE Network account, required to access any WWE Network stream.",
)
@pluginargument(
    "password",
    required=True,
    sensitive=True,
    metavar="PASSWORD",
    help="A WWE Network account password to use with --wwenetwork-email.",
)
class WWENetwork(Plugin):
    site_config_re = re.compile(r"""">window.__data = (\{.*?\})</script>""")
    stream_url = "https://dce-frontoffice.imggaming.com/api/v2/stream/{id}"
    live_url = "https://dce-frontoffice.imggaming.com/api/v2/event/live"
    login_url = "https://dce-frontoffice.imggaming.com/api/v2/login"

    API_KEY = "cca51ea0-7837-40df-a055-75eb6347b2e7"

    customer_id = 16

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.session.http.headers.update({"User-Agent": useragents.CHROME})
        self.auth_token = None

    def request(self, method, url, **kwargs):
        headers = kwargs.pop("headers", {})
        headers.update({"x-api-key": self.API_KEY,
                        "Origin": "https://network.wwe.com",
                        "Referer": "https://network.wwe.com/signin",
                        "Accept": "application/json",
                        "Realm": "dce.wwe"})
        if self.auth_token:
            headers["Authorization"] = "Bearer {0}".format(self.auth_token)

        kwargs["raise_for_status"] = False
        log.debug("API request: {0} {1}".format(method, url))
        res = self.session.http.request(method, url, headers=headers, **kwargs)
        data = self.session.http.json(res)

        if "status" in data and data["status"] != 200:
            log.debug("API request failed: {0}:{1} ({2})".format(
                data["status"],
                data.get("code"),
                "; ".join(data.get("messages", [])),
            ))
        return data

    def login(self, email, password):
        log.debug("Attempting login as {0}".format(email))
        # sets some required cookies to login
        data = self.request("POST", self.login_url,
                            data=json.dumps({"id": email, "secret": password}),
                            headers={"Content-Type": "application/json"})
        if "authorisationToken" in data:
            self.auth_token = data["authorisationToken"]

        return self.auth_token

    def _get_media_info(self, content_id):
        """
        Get the info about the content, based on the ID
        :param content_id: contentId for the video
        :return:
        """
        info = self.request("GET", self.stream_url.format(id=content_id))
        return self.request("GET", info.get("playerUrlCallback"))

    def _get_video_id(self, stream_id):
        live_id = self._get_live_id(stream_id)
        if not live_id:
            return "vod/{0}".format(stream_id)

        return live_id

    def _get_live_id(self, stream_id):
        log.debug("Loading live event")
        res = self.request("GET", self.live_url)
        for event in res.get("events", []):
            if str(event["id"]) == stream_id:
                return "event/{sportId}/{propertyId}/{tournamentId}/{id}".format(**event)

    def _get_streams(self):
        if not self.login(self.get_option("email"), self.get_option("password")):
            raise PluginError("Login failed")

        try:
            start_point = int(float(dict(parse_qsl(urlparse(self.url).query)).get("startPoint", 0.0)))
            if start_point > 0:
                log.info("Stream will start at {0}".format(seconds_to_hhmmss(start_point)))
        except ValueError:
            start_point = 0

        stream_id = self.match.group("stream_id")
        content_id = self._get_video_id(stream_id)

        if content_id:
            log.debug("Found content ID: {0}".format(content_id))
            info = self._get_media_info(content_id)
            if info.get("hlsUrl"):
                yield from HLSStream.parse_variant_playlist(
                    self.session,
                    info["hlsUrl"],
                    start_offset=start_point,
                ).items()
            else:
                log.error("Could not find the HLS URL")


__plugin__ = WWENetwork
