from typing import List
from typing import Optional

from ytdl_sub.config.plugin.plugin import Plugin
from ytdl_sub.config.validators.options import OptionsValidator
from ytdl_sub.entries.entry import Entry
from ytdl_sub.utils.ffmpeg import FFMPEG
from ytdl_sub.utils.file_handler import FileHandler
from ytdl_sub.utils.file_handler import FileMetadata
from ytdl_sub.utils.logger import Logger
from ytdl_sub.validators.string_formatter_validators import OverridesBooleanFormatterValidator

logger = Logger.get("square-thumbnail")


class SquareThumbnailOptions(OverridesBooleanFormatterValidator, OptionsValidator):
    """
    Whether to make thumbnails square. Supports both file and embedded-based thumbnails. Ideal
    for representing audio albums.

    :Usage:

    .. code-block:: yaml

       square_thumbnail: True
    """


class SquareThumbnailPlugin(Plugin[SquareThumbnailOptions]):
    plugin_options_type = SquareThumbnailOptions

    @property
    def _square_thumbnail(self) -> bool:
        return self.overrides.apply_formatter(self.plugin_options, expected_type=bool)

    @classmethod
    def _convert_to_square_thumbnail(cls, entry: Entry) -> None:
        thumbnail_path = entry.get_download_thumbnail_path()
        tmp_file_path = FFMPEG.tmp_file_path(thumbnail_path)
        try:
            ffmpeg_args: List[str] = [
                "-i",
                thumbnail_path,
                "-c:v",
                "mjpeg",
                "-qmin",
                "1",
                "-qscale:v",
                "1",
                "-vf",
                "crop=min(iw\\,ih):min(iw\\,ih)",
                "-bitexact",  # for reproducibility
                tmp_file_path,
            ]
            FFMPEG.run(ffmpeg_args)
            FileHandler.move(tmp_file_path, thumbnail_path)
        finally:
            FileHandler.delete(tmp_file_path)

    def post_process_entry(self, entry: Entry) -> Optional[FileMetadata]:
        """
        Maybe make the thumbnail square
        """
        if not self._square_thumbnail:
            return None

        if not self.is_dry_run:
            if not entry.is_thumbnail_downloaded():
                logger.warning(
                    "Cannot make a square thumbnail for '%s' because it is not available",
                    entry.title,
                )
                return None

            self._convert_to_square_thumbnail(entry)

        return FileMetadata("Square thumbnail")
