# SPDX-FileCopyrightText: (c) 2022  Karl Kroening (kkroening)
# SPDX-FileCopyrightText: (c) TagStudio Contributors
# SPDX-License-Identifier: GPL-3.0-only
# Vendored from ffmpeg-python and ffmpeg-python PR#790 by amamic1803


import contextlib
import json
import os
import platform
import subprocess
from shutil import which

import ffmpeg
import structlog

from tagstudio.core.utils.silent_subprocess import silent_popen, silent_run

logger = structlog.get_logger(__name__)

user = os.environ.get("USER", None)
FFMPEG_MACOS_LOCATIONS: list[str] = [
    "",
    "/opt/homebrew/bin/",
    "/usr/local/bin/",
    f"/etc/profiles/per-user/{user}/bin",
]


# TODO: Make this more intuitive to use in other classes
def _get_ffprobe_location() -> str:
    cmd: str = "ffprobe"
    if platform.system() == "Darwin":
        for loc in FFMPEG_MACOS_LOCATIONS:
            if which(loc + cmd):
                cmd = loc + cmd
                break
    logger.info(
        f"[FFmpeg] Using FFprobe location: {cmd}{' (Found)' if which(cmd) else ' (Not Found)'}"
    )
    return cmd


# TODO: Make this more intuitive to use in other classes
def _get_ffmpeg_location() -> str:
    cmd: str = "ffmpeg"
    if platform.system() == "Darwin":
        for loc in FFMPEG_MACOS_LOCATIONS:
            if which(loc + cmd):
                cmd = loc + cmd
                break
    logger.info(
        f"[FFmpeg] Using FFmpeg location: {cmd}{' (Found)' if which(cmd) else ' (Not Found)'}"
    )
    return cmd


FFPROBE_CMD = _get_ffprobe_location()
FFMPEG_CMD = _get_ffmpeg_location()


def probe(filename, cmd=FFPROBE_CMD, timeout=None, **kwargs):
    """Run ffprobe on the specified file and return a JSON representation of the output.

    Raises:
        :class:`ffmpeg.Error`: if ffprobe returns a non-zero exit code,
            an :class:`Error` is returned with a generic error message.
            The stderr output can be retrieved by accessing the
            ``stderr`` property of the exception.
    """
    args = [cmd, "-show_format", "-show_streams", "-of", "json"]
    args += ffmpeg._utils.convert_kwargs_to_cmd_line_args(kwargs)  # pyright: ignore[reportAttributeAccessIssue]
    args += [filename]

    # PATCHED
    p = silent_popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    communicate_kwargs = {}
    if timeout is not None:
        communicate_kwargs["timeout"] = timeout
    out, err = p.communicate(**communicate_kwargs)
    if p.returncode != 0:
        raise ffmpeg.Error("ffprobe", out, err)
    return json.loads(out.decode("utf-8"))


def version():
    """Checks the version of FFmpeg and FFprobe and returns None if they dont exist."""
    version: dict[str, str | None] = {"ffmpeg": None, "ffprobe": None}

    if which(FFMPEG_CMD):
        ret = silent_run([FFMPEG_CMD, "-version"], shell=False, capture_output=True, text=True)
        if ret.returncode == 0:
            with contextlib.suppress(Exception):
                version["ffmpeg"] = str(ret.stdout).split(" ")[2]

    if which(FFPROBE_CMD):
        ret = silent_run([FFPROBE_CMD, "-version"], shell=False, capture_output=True, text=True)
        if ret.returncode == 0:
            with contextlib.suppress(Exception):
                version["ffprobe"] = str(ret.stdout).split(" ")[2]

    return version
