import asyncio
import hashlib
import logging
import os
import tempfile
from pathlib import Path

from .config import Config
from .ffprobe import ffprobe
from .Utils import StreamingError

LOG = logging.getLogger("player.segments")


class Segments:
    def __init__(self, download_path: str, index: int, duration: float, vconvert: bool, aconvert: bool):
        config = Config.get_instance()
        self.download_path = download_path
        self.index = int(index)
        self.duration = float(duration)
        self.vconvert = bool(vconvert)
        self.aconvert = bool(aconvert)
        self.vcodec = config.streamer_vcodec
        self.acodec = config.streamer_acodec
        # sadly due to unforeseen circumstances, we have to convert the video for now.
        self.vconvert = True
        self.aconvert = True

    async def stream(self, file: Path) -> bytes:
        try:
            ff = await ffprobe(file)
        except UnicodeDecodeError:
            pass

        tmpDir: str = tempfile.gettempdir()
        tmpFile = os.path.join(tmpDir, f'ytptube_stream.{hashlib.sha256(str(file).encode("utf-8")).hexdigest()}')

        if not os.path.exists(tmpFile):
            os.symlink(file, tmpFile)

        if self.index == 0:
            startTime: float = f"{0:.6f}"
        else:
            startTime: float = f"{self.duration * self.index:.6f}"

        fargs = []
        fargs.append("-xerror")
        fargs.append("-hide_banner")
        fargs.append("-loglevel")
        fargs.append("error")

        fargs.append("-ss")
        fargs.append(str(startTime if startTime else "0.00000"))
        fargs.append("-t")
        fargs.append(str(f"{self.duration:.6f}"))

        fargs.append("-copyts")

        fargs.append("-i")
        fargs.append(f"file:{tmpFile}")
        fargs.append("-map_metadata")
        fargs.append("-1")

        # video section.
        if ff.has_video():
            fargs.append("-pix_fmt")
            fargs.append("yuv420p")
            fargs.append("-g")
            fargs.append("52")

            fargs.append("-map")
            fargs.append("0:v:0")
            fargs.append("-strict")
            fargs.append("-2")

            fargs.append("-codec:v")
            fargs.append(self.vcodec if self.vconvert else "copy")

        # audio section.
        if ff.has_audio():
            fargs.append("-map")
            fargs.append("0:a:0")
            fargs.append("-codec:a")
            fargs.append(self.acodec if self.aconvert else "copy")

        fargs.append("-sn")

        fargs.append("-muxdelay")
        fargs.append("0")
        fargs.append("-f")
        fargs.append("mpegts")
        fargs.append("pipe:1")

        LOG.debug(f"Streaming '{file}' segment '{self.index}'. ffmpeg: {' '.join(fargs)}")

        proc = await asyncio.subprocess.create_subprocess_exec(
            "ffmpeg",
            *fargs,
            stdin=asyncio.subprocess.DEVNULL,
            stdout=asyncio.subprocess.PIPE,
            stderr=asyncio.subprocess.PIPE,
        )

        data, err = await proc.communicate()

        if 0 != proc.returncode:
            LOG.error(f"Failed to stream '{file}' segment '{self.index}'. {err.decode('utf-8')}.")
            msg = f"Failed to stream '{file}' segment '{self.index}'."
            raise StreamingError(msg)

        return data
