# mpvqc_gui_embedded.py
# PyQt6 + mpv (embedded). English UI. No bottom label—video only.
# Reqs: pip install mpv PyQt6  (and have libmpv/mpv-2.dll available on Windows)

import os, re, sys
from typing import Optional, Tuple
from PyQt6 import QtWidgets, QtGui, QtCore
import mpv  # python-mpv

VIDEO_EXTS = ('.mkv', '.mp4', '.avi', '.mov', '.m2ts', '.ts', '.webm', '.flv')

# --------- ASS helpers ---------
def _read_text(path: str) -> Optional[str]:
    try:
        with open(path, 'r', encoding='utf-8-sig', errors='ignore') as f:
            return f.read()
    except Exception:
        return None

def _parse_apg(txt: str) -> dict:
    m_sec = re.search(r'^\[Aegisub Project Garbage\]\s*$', txt, re.I | re.M)
    if not m_sec: return {}
    start = m_sec.end()
    m_next = re.search(r'^\[.+?\]\s*$', txt[start:], re.M)
    end = start + m_next.start() if m_next else len(txt)
    meta = {}
    for line in txt[start:end].splitlines():
        line=line.strip()
        if not line or line.startswith(';') or ':' not in line: continue
        k,v = line.split(':',1)
        meta[k.strip()] = v.strip().strip('"')
    return meta

def extract_media_paths(sub_path: str) -> Tuple[Optional[str], Optional[str]]:
    txt = _read_text(sub_path)
    if not txt: return None, None
    meta = _parse_apg(txt)
    v = meta.get('Video File') or meta.get('VideoFile') or meta.get('Video')
    a = meta.get('Audio File') or meta.get('AudioFile') or meta.get('Audio')
    return (v.strip() if v else None, a.strip() if a else None)

def resolve_existing_video(sub_path: str, video_candidate: Optional[str]) -> Optional[str]:
    """
    Rules:
      - Absolute/relative path -> resolve and verify.
      - Filename only -> look ONLY in the same directory as the .ass (also try common video extensions).
      - If not found -> None (stay silent).
    """
    if not video_candidate:
        return None
    cand = video_candidate.replace('/', os.sep).strip('"').strip()
    base_dir = os.path.dirname(os.path.abspath(sub_path))

    # Absolute
    if os.path.isabs(cand) and os.path.isfile(cand):
        return os.path.normpath(cand)

    # Relative (contains separators)
    if os.sep in cand or ('/' in video_candidate) or ('\\' in video_candidate):
        rel = os.path.normpath(os.path.join(base_dir, cand))
        return rel if os.path.isfile(rel) else None

    # Filename only -> same dir
    name = os.path.basename(cand)
    p = os.path.join(base_dir, name)
    if os.path.isfile(p):
        return os.path.normpath(p)

    # Try same name with known extensions
    name_no_ext, ext = os.path.splitext(name)
    if ext.lower() not in VIDEO_EXTS:
        for e in VIDEO_EXTS:
            p2 = os.path.join(base_dir, name_no_ext + e)
            if os.path.isfile(p2):
                return os.path.normpath(p2)
    return None

# --------- Main window ---------
class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("mpvQC — Embedded Demo")
        self.resize(1280, 800)

        # Video-only central area
        self.video_container = QtWidgets.QWidget(self)
        self.video_container.setStyleSheet("background:#111;")
        self.video_container.setSizePolicy(
            QtWidgets.QSizePolicy.Policy.Expanding,
            QtWidgets.QSizePolicy.Policy.Expanding
        )

        # Central widget with zero margins so the video grows maximally
        central = QtWidgets.QWidget(self)
        lay = QtWidgets.QVBoxLayout(central)
        lay.setContentsMargins(0, 0, 0, 0)
        lay.setSpacing(0)
        lay.addWidget(self.video_container)
        self.setCentralWidget(central)

        # Menu (English)
        menubar = self.menuBar()
        menu_video = menubar.addMenu("&Video")

        act_open_video = QtGui.QAction("Open &Video...", self)
        act_open_video.setShortcut(QtGui.QKeySequence("Ctrl+O"))
        act_open_video.triggered.connect(self.open_video_dialog)

        act_open_subs = QtGui.QAction("Open &Subtitle(s)", self)
        act_open_subs.setShortcut(QtGui.QKeySequence("Ctrl+L"))
        act_open_subs.triggered.connect(self.open_subtitles_dialog)

        menu_video.addAction(act_open_video)
        menu_video.addAction(act_open_subs)

        # State
        self.loaded_sub_path: Optional[str] = None
        self.loaded_video_path: Optional[str] = None

        # mpv embedded
        self._init_mpv()

        # Optional: hide status bar to maximize vertical space
        # self.statusBar().hide()

    # ---- mpv ----
    def _init_mpv(self):
        wid = int(self.video_container.winId())
        self.mpv = mpv.MPV(
            wid=wid,
            osc='yes',
            hwdec='auto-safe',
            vo='gpu',
            keep_open='yes',
            ytdl='no',
        )
        self.mpv['keep-open'] = True
        self.mpv['pause'] = True
        self.mpv['sub-visibility'] = True
        # Keep aspect ratio, letterbox when needed
        self.mpv['keepaspect-window'] = True

    def load_video_real(self, video_path: str, sub_path: Optional[str] = None):
        """Load video and (optionally) attach/select external .ass."""
        self.loaded_video_path = video_path
        self.mpv.command('loadfile', video_path, 'replace')
        sub_path = sub_path or self.loaded_sub_path
        if sub_path and os.path.isfile(sub_path):
            try:
                self.mpv.command('sub-add', sub_path, 'select')
                self.mpv['sub-visibility'] = True
            except Exception:
                pass
        self.mpv['pause'] = False

    def add_subtitles_only(self, sub_path: str):
        if not os.path.isfile(sub_path):
            return
        try:
            self.mpv.command('sub-add', sub_path, 'select')
            self.mpv['sub-visibility'] = True
        except Exception:
            pass

    # ---- Menu actions ----
    def open_video_dialog(self):
        path, _ = QtWidgets.QFileDialog.getOpenFileName(
            self, "Select video", "", "Video (*.mkv *.mp4 *.avi *.mov *.m2ts *.ts *.webm *.flv)"
        )
        if path:
            self.load_video_real(path, sub_path=self.loaded_sub_path)

    def open_subtitles_dialog(self):
        path, _ = QtWidgets.QFileDialog.getOpenFileName(
            self, "Select subtitle(s)", "", "ASS/SSA Subtitles (*.ass *.ssa)"
        )
        if not path:
            return

        self.loaded_sub_path = path

        # Check if the .ass links a video we can load
        v_raw, _ = extract_media_paths(path)
        v_resolved = resolve_existing_video(path, v_raw)

        if v_resolved and os.path.isfile(v_resolved):
            msg = (
                "A linked video was found for this subtitle file:\n\n"
                f"{v_resolved}\n\n"
                "Do you want to load it?"
            )
            if self.ask_yes_no(msg, title="Linked video detected"):
                self.load_video_real(v_resolved, sub_path=path)
                return

        # If no video was loaded, but a video is already playing, just attach subs
        if self.loaded_video_path:
            self.add_subtitles_only(path)

    # ---- Dialog helpers ----
    def ask_yes_no(self, text: str, title: str = "Confirm") -> bool:
        box = QtWidgets.QMessageBox(self)
        box.setIcon(QtWidgets.QMessageBox.Icon.Question)
        box.setWindowTitle(title)
        box.setText(text)
        box.setStandardButtons(
            QtWidgets.QMessageBox.StandardButton.Yes |
            QtWidgets.QMessageBox.StandardButton.No
        )
        box.button(QtWidgets.QMessageBox.StandardButton.Yes).setText("Yes")
        box.button(QtWidgets.QMessageBox.StandardButton.No).setText("No")
        return box.exec() == QtWidgets.QMessageBox.StandardButton.Yes

def main():
    app = QtWidgets.QApplication(sys.argv)
    app.setApplicationName("mpvQC — Embedded Demo")
    app.setOrganizationName("CiferrC")
    w = MainWindow()
    w.show()
    sys.exit(app.exec())

if __name__ == "__main__":
    main()
