import itertools
import logging
import re
from urllib.parse import urlparse

from streamlink.plugin import Plugin, PluginError, pluginmatcher
from streamlink.plugin.api import validate
from streamlink.stream.hls import HLSStream
from streamlink.utils.parse import parse_qsd
from streamlink.utils.url import update_scheme

log = logging.getLogger(__name__)


@pluginmatcher(re.compile(
    r"https?://(?:[\w-]+\.)?delfi\.(?P<tld>lt|lv|ee)"
))
class Delfi(Plugin):
    _api = {
        "lt": "https://g2.dcdn.lt/vfe/data.php",
        "lv": "https://g.delphi.lv/vfe/data.php",
        "ee": "https://g4.nh.ee/vfe/data.php",
    }

    def _get_streams_api(self, video_id):
        log.debug(f"Found video ID: {video_id}")

        tld = self.match.group("tld")
        try:
            data = self.session.http.get(
                self._api.get(tld, "lt"),
                params=dict(video_id=video_id),
                schema=validate.Schema(
                    validate.parse_json(),
                    {
                        "success": True,
                        "data": {
                            "versions": {
                                str: validate.all(
                                    [{
                                        "type": str,
                                        "src": str,
                                    }],
                                    validate.filter(lambda item: item["type"] == "application/x-mpegurl")
                                )
                            }
                        }
                    },
                    validate.get(("data", "versions"))
                )
            )
        except PluginError:
            log.error("Failed to get streams from API")
            return

        for stream in itertools.chain(*data.values()):
            src = update_scheme("https://", stream["src"], force=False)
            yield from HLSStream.parse_variant_playlist(self.session, src).items()

    def _get_streams_delfi(self, src):
        try:
            data = self.session.http.get(src, schema=validate.Schema(
                validate.parse_html(),
                validate.xml_xpath_string(".//script[contains(text(),'embedJs.setAttribute(')][1]/text()"),
                validate.any(None, validate.all(
                    str,
                    validate.transform(re.compile(r"embedJs\.setAttribute\('src',\s*'(.+?)'").search),
                    validate.any(None, validate.all(
                        validate.get(1),
                        validate.transform(lambda url: parse_qsd(urlparse(url).fragment)),
                        {"stream": str},
                        validate.get("stream"),
                        validate.parse_json(),
                        {"versions": [{
                            "hls": str
                        }]},
                        validate.get("versions")
                    ))
                ))
            ))
        except PluginError:
            log.error("Failed to get streams from iframe")
            return

        for stream in data:
            src = update_scheme("https://", stream["hls"], force=False)
            yield from HLSStream.parse_variant_playlist(self.session, src).items()

    def _get_streams(self):
        root = self.session.http.get(self.url, schema=validate.Schema(
            validate.parse_html()
        ))

        video_id = root.xpath("string(.//div[@data-provider='dvideo'][@data-id][1]/@data-id)")
        if video_id:
            return self._get_streams_api(str(video_id))

        yt_id = root.xpath("string(.//script[contains(@src,'/yt.js')][@data-video]/@data-video)")
        if yt_id:
            return self.session.streams(f"https://www.youtube.com/watch?v={yt_id}")

        yt_iframe = root.xpath("string(.//iframe[starts-with(@src,'https://www.youtube.com/')][1]/@src)")
        if yt_iframe:
            return self.session.streams(str(yt_iframe))

        delfi = root.xpath("string(.//iframe[@name='delfi-stream'][@src][1]/@src)")
        if delfi:
            return self._get_streams_delfi(str(delfi))


__plugin__ = Delfi
