import os
import re
import shutil
import subprocess
from pathlib import Path
from Core import Bootstrap


class MkvMuxer(Bootstrap):
    """
    Class responsible for multiplexing (muxing) video, audio, and subtitle files
    into a single MKV file using the mkvmerge tool.

    Attributes:
        title (str): Output MKV file name.
        media_dir (Path): Directory containing decrypted media files.
        download_dir (Path): Output directory where the final MKV will be saved.
        mkvmerge_path (str): Path to the mkvmerge executable.
    """

    def __init__(self, name: str, media_dir: str, media_type: str = "movie"):
        """
        Initialize the muxer with basic file info.

        Args:
            name (str): The final MKV file name.
            media_dir (str): Path to the directory containing media files.
            media_type (str): Type of media (default is "movie").
        """
        super().__init__()
        self.media_dir = Path(media_dir)
        self.download_dir = Path(self.get_item("download_dir")) / media_type
        self.title = name
        self.mkvmerge_path = os.path.join(os.getcwd(), "bin", "mkvmerge.exe")

    def __enter__(self):
        return self

    def call(self):
        """
        Executes the muxing process by combining the video file with
        all corresponding audio and subtitle tracks into a single MKV.
        """
        video_file = None
        audio_files = []
        subtitle_files = []
        languages = []

        for file in self.media_dir.glob("**/*"):
            if "_decrypted" not in str(file):
                continue

            if "video_" in str(file):
                video_file = file

            elif "audio_" in str(file):
                audio_language = re.search(r"audio_(.*?)_decrypted", str(file)).group(1)
                default_track = False
                if audio_language == self.default_language:
                    default_track = True
                code, name = self.extract_language_code(audio_language)
                languages.append(code)
                audio_files += [
                    f'--language 0:{code}',
                    f'--track-name 0:"{name}"',
                    f'--default-track 0:"{default_track}"',
                    f'"{str(file)}"'
                ]

            elif "subtitle_" in str(file):
                subtitle_language = re.search(r"subtitle_(.*?)_decrypted", str(file)).group(1)
                default_track = False
                forced_track = False
                if subtitle_language == self.default_language:
                    default_track = True
                    if "_forced" in str(file):
                        forced_track = True
                code, name = self.extract_language_code(subtitle_language)
                subtitle_files += [
                    f'--language 0:"{code}"',
                    f'--track-name 0:"{name}"',
                    f'--forced-track 0:"{forced_track}"',
                    f'--default-track 0:"{default_track}"',
                    f'"{str(file)}"'
                ]

        if video_file is None:
            self.error("No video file found to mux")
            return

        mkv_file = self.download_dir / f"{self.title}.mkv"

        if mkv_file.exists():
            self.warning(f"MKV file already exists: {mkv_file}")
            # return

        name = self.shorten_name(os.path.basename(str(self.title)))
        mkv_file = mkv_file.with_name(f"{name}.mkv")

        tags = Path(os.getcwd()) / "Core" / "tags.xml"

        command = [
            self.mkvmerge_path,
            "-o", f'"{str(mkv_file)}"',
            "--title", f'"{name}"',
            "--language", "0:und",
            "--track-name", f'0:"{name}"',
            f'"{str(video_file)}"',
            *audio_files,
            *subtitle_files,
        ]

        # Attach cover image if available
        attachment = []
        cover = self.get_item("cover")
        if cover and os.path.exists(cover):
            attachment += [
                '--attachment-name "Cover Image"',
                f'--attach-file "{cover}"'
            ]

        command += attachment
        command += [
            "-q",
            f'--global-tags "{str(tags)}"'
        ]

        try:
            self.info("Starting muxing...")
            subprocess.run(" ".join(command), check=True)
            self.success(f"MKV file muxed successfully: {mkv_file}")
            shutil.rmtree(self.media_dir)
        except subprocess.CalledProcessError as e:
            self.error(f"Error during muxing: {e.stderr}")
