#!/usr/bin/env python3
"""Kurgulu Eğitim önizlemesi (render yok, orijinal 4K dosyalar + miks).

Premiere'deki çoklu kamera gibi: iki kamera arkada sürekli senkron oynar, kesimde sadece görünen kamera değişir
(takılma olmaz). Sessizlik atlanan yerlerde hepsi birlikte sarılır. Kurgu: kurgu/kurgu.json (medya/kurgu.py üretir).

Kullanım: python3 kurgu_oynatici.py [başlangıç dakikası]
Tuşlar: Y yan yana (solda kurgu, sağda diğer kamera) · Boşluk oynat/duraklat · ← → 5 sn · ↑ ↓ 1 dk · PgUp/PgDn önceki/sonraki kesim · R renk düzeltmesi · F tam ekran
"""
import bisect, fcntl, json, os, sys, tempfile, time

sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from oynatici import Mpv, Iz, LUT, saat                      # eski oynatıcının senkron parçaları (dosyası değişmez)
from PyQt6.QtCore import Qt, QTimer, QRectF
from PyQt6.QtGui import QColor, QFont, QPainter, QKeySequence, QShortcut
from PyQt6.QtWidgets import QApplication, QHBoxLayout, QLabel, QPushButton, QVBoxLayout, QWidget

KOK = os.path.dirname(os.path.abspath(__file__))
RENK = {"A": "#4f8ef7", "B": "#3cc48a"}


def dk(t):
    t = int(max(t, 0)); return f"{t // 3600}:{t % 3600 // 60:02d}:{t % 60:02d}"


class Cizgi(QWidget):
    def __init__(self, ana):
        super().__init__(); self.ana = ana; self.setMinimumHeight(46); self.setMouseTracking(True)

    def t_x(self, t): return 8 + t / self.ana.toplam * (self.width() - 16)
    def x_t(self, x): return min(max((x - 8) / (self.width() - 16), 0), 1) * self.ana.toplam

    def mousePressEvent(self, e): self.ana.git(self.x_t(e.position().x()))

    def mouseMoveEvent(self, e):
        t = self.x_t(e.position().x())
        if e.buttons() & Qt.MouseButton.LeftButton: self.ana.git(t)
        s = self.ana.kesit(t); self.setToolTip(f"{dk(t)}  ·  Kamera {s['kamera']}  ·  {saat(self.ana.gercek(t))}  ·  {s['bolum']}")

    def paintEvent(self, _):
        p = QPainter(self); p.fillRect(self.rect(), QColor("#161616")); h = self.height()
        for s in self.ana.kesitler:
            x0, x1 = self.t_x(s["e0"]), self.t_x(s["e0"] + s["n"])
            p.fillRect(QRectF(x0, 6, max(x1 - x0 - 0.5, 0.8), 16), QColor(RENK[s["kamera"]]))
        p.setFont(QFont("Sans", 8)); p.setPen(QColor("#999"))
        onceki = None
        for s in self.ana.kesitler:
            if s["bolum"] != onceki:
                x = self.t_x(s["e0"]); p.drawLine(int(x), 24, int(x), h); p.drawText(int(x) + 3, h - 4, s["bolum"]); onceki = s["bolum"]
        x = self.t_x(self.ana.konum()); p.setPen(QColor("#ff4040")); p.drawLine(int(x), 0, int(x), h)


class Kurgu(QWidget):
    def __init__(self, bas_dk):
        super().__init__()
        k = json.load(open(os.path.join(KOK, "kurgu", "kurgu.json"), encoding="utf-8"))
        self.kesitler = []; e = 0.0
        for s in k["kesitler"]:
            n = s["son"] - s["bas"]; self.kesitler.append(dict(s, e0=e, n=n)); e += n
        self.e0 = [s["e0"] for s in self.kesitler]; self.toplam = e
        self.setWindowTitle("Eğitim 01 – kurgu önizleme")
        self.calisiyor = False; self.t0 = bas_dk * 60; self.m0 = time.monotonic(); self.renk = True; self.son_i = -1; self.yan_yana = True

        # iki kamera üst üste; görünen öne alınır, öbürü arkada oynamaya devam eder
        self.alan = QWidget(); self.alan.setStyleSheet("background:#000"); self.alan.setMinimumSize(640, 360)
        self.ekran = {}
        for kam in "AB":
            w = QWidget(self.alan); w.setAttribute(Qt.WidgetAttribute.WA_NativeWindow); w.setStyleSheet("background:#000")
            self.ekran[kam] = w
        self.bilgi = QLabel(); self.bilgi.setStyleSheet("color:#ddd; font: 14px monospace")
        self.dugme = QPushButton("▶"); self.dugme.setFixedWidth(44); self.dugme.clicked.connect(self.oynat_duraklat)
        self.renk_d = QPushButton("Renk düzeltme: açık"); self.renk_d.clicked.connect(self.renk_degis)
        self.cizgi = Cizgi(self)
        alt = QHBoxLayout(); alt.addWidget(self.dugme); alt.addWidget(self.bilgi, 1); alt.addWidget(self.renk_d)
        ana = QVBoxLayout(self); ana.setContentsMargins(4, 4, 4, 4)
        ana.addWidget(self.alan, 1); ana.addWidget(self.cizgi); ana.addLayout(alt)
        self.setStyleSheet("QWidget{background:#202020;color:#ddd} QPushButton{padding:4px 8px;background:#333;border:1px solid #444}")
        self.resize(1600, 980); self.show(); QApplication.processEvents(); self.yerlestir()

        z = json.load(open(os.path.join(KOK, "medya", "zaman.json"), encoding="utf-8"))["bolumler"]["Eğitim"]
        self.kam = {}
        for kam in "AB":
            m = Mpv(wid=self.ekran[kam].winId(), ses_yok=True, ad=f"kurgu{kam}")
            m.ayarla("lut", LUT); m.ayarla("lut-type", "native")
            self.kam[kam] = Iz(f"Kamera {kam}", z["video"][kam], m)
        self.ses = Iz("Miks", [k["miks"]], Mpv(ad="kurguSes"))

        kis = {"Space": self.oynat_duraklat, "Left": lambda: self.git(self.konum() - 5), "Right": lambda: self.git(self.konum() + 5),
               "Up": lambda: self.git(self.konum() + 60), "Down": lambda: self.git(self.konum() - 60),
               "PgUp": lambda: self.git(self.kesit(self.konum() - 0.5)["e0"]),
               "PgDown": lambda: self.git(self.kesit(self.konum())["e0"] + self.kesit(self.konum())["n"] + 0.01),
               "R": self.renk_degis, "F": lambda: self.showNormal() if self.isFullScreen() else self.showFullScreen(),
               "Esc": self.showNormal, "Y": self.yan_degis}
        for tus, f in kis.items():
            QShortcut(QKeySequence(tus), self, f)
        self.git(self.t0)
        self.hizli = QTimer(self); self.hizli.timeout.connect(self.tik); self.hizli.start(20)
        self.yavas = QTimer(self); self.yavas.timeout.connect(self.hizala); self.yavas.start(250)

    # --- zaman
    def konum(self):
        return min(self.t0 + (time.monotonic() - self.m0), self.toplam - 0.02) if self.calisiyor else self.t0

    def indeks(self, t): return max(bisect.bisect_right(self.e0, t) - 1, 0)
    def kesit(self, t): return self.kesitler[self.indeks(t)]

    def gercek(self, t):
        s = self.kesit(t); return s["bas"] + (t - s["e0"])

    def izler(self): return [self.kam["A"], self.kam["B"], self.ses]

    def git(self, t):
        self.t0 = min(max(t, 0), self.toplam - 0.05); self.m0 = time.monotonic()
        g = self.gercek(self.t0)
        for iz in self.izler():
            iz.hizala(g, self.calisiyor, 1.0, zorla=True)
        self.son_i = -1; self.tik()

    def oynat_duraklat(self):
        self.t0 = self.konum(); self.m0 = time.monotonic(); self.calisiyor = not self.calisiyor
        for iz in self.izler():
            iz.mpv.ayarla("pause", not self.calisiyor)
        self.git(self.t0); self.dugme.setText("❚❚" if self.calisiyor else "▶")

    def hizala(self):
        # Ana saat sestir: oynarken ses hiç sarılmaz (sarma duyulur), saat sesin konumuna göre düzeltilir,
        # görüntü sese uyar. Ses ancak 0.5 sn'den fazla koparsa (ör. dosya değişimi) yeniden konumlanır.
        t = self.konum()
        if self.calisiyor:
            p = self.ses.mpv.oku("time-pos")
            if isinstance(p, (int, float)) and self.ses.mpv.klip is not None:
                gercek_ses = self.ses.mpv.klip["bas"] + p
                i = self.indeks(t)
                for j in range(max(i - 1, 0), min(i + 3, len(self.kesitler))):
                    s = self.kesitler[j]
                    if s["bas"] - 0.02 <= gercek_ses < s["son"] + 0.02:
                        t_ses = s["e0"] + (gercek_ses - s["bas"])
                        if abs(t_ses - t) < 0.5:
                            self.t0, self.m0 = t_ses, time.monotonic(); t = t_ses
                        break
        g = self.gercek(t)
        for iz in (self.kam["A"], self.kam["B"]):
            iz.hizala(g, self.calisiyor, 1.0)
        k = self.ses.bul(g); m = self.ses.mpv
        if k is not None and (m.klip is not k or not self.calisiyor):
            self.ses.hizala(g, self.calisiyor, 1.0)
        elif k is not None and self.calisiyor:
            p = m.oku("time-pos")
            if isinstance(p, (int, float)) and abs(p - (g - k["bas"])) > 0.5:
                m.komut("seek", g - k["bas"], "absolute+exact")

    def tik(self):
        t = self.konum()
        if self.calisiyor and t >= self.toplam - 0.05:
            self.oynat_duraklat(); return
        i = self.indeks(t)
        if i != self.son_i:
            s = self.kesitler[i]
            if self.son_i >= 0 and i == self.son_i + 1 and abs(self.kesitler[self.son_i]["son"] - s["bas"]) > 0.1:
                g = self.gercek(t)                                   # sessizlik atlandı: hepsini sar
                for iz in self.izler():
                    iz.hizala(g, self.calisiyor, 1.0, zorla=True)
            self.son_i = i; self.yerlestir()
        s = self.kesitler[i]
        self.bilgi.setText(f"{dk(t)} / {dk(self.toplam)}   Kamera {s['kamera']} · {os.path.basename(s['yol'])} · {saat(self.gercek(t))} · {s['bolum']}   kesim {i + 1}/{len(self.kesitler)}")
        self.cizgi.update()

    # --- görünüm
    def yerlestir(self):
        """Tek ekran: görünen kamera öne alınır. Yan yana (Y): solda kurgu, sağda o an kullanılmayan kamera."""
        W_, H_ = self.alan.width(), self.alan.height()
        aktif = self.kesitler[self.son_i]["kamera"] if self.son_i >= 0 else "A"
        if self.yan_yana:
            yarim = W_ // 2 - 2
            self.ekran[aktif].setGeometry(0, 0, yarim, H_)
            self.ekran["B" if aktif == "A" else "A"].setGeometry(W_ - yarim, 0, yarim, H_)
        else:
            for w in self.ekran.values():
                w.setGeometry(0, 0, W_, H_)
            self.ekran[aktif].raise_()

    def yan_degis(self):
        self.yan_yana = not self.yan_yana; self.yerlestir()

    def resizeEvent(self, e):
        super().resizeEvent(e); self.yerlestir()

    def renk_degis(self):
        self.renk = not self.renk
        for kam in "AB":
            self.kam[kam].mpv.ayarla("lut", LUT if self.renk else "")
        self.renk_d.setText(f"Renk düzeltme: {'açık' if self.renk else 'kapalı (Log)'}")

    def closeEvent(self, e):
        self.hizli.stop(); self.yavas.stop()
        for iz in self.izler():
            iz.mpv.kapat()
        super().closeEvent(e)


if __name__ == "__main__":
    kilit = open(os.path.join(tempfile.gettempdir(), "egitim-kurgu-oynatici.lock"), "w")
    try:
        fcntl.flock(kilit, fcntl.LOCK_EX | fcntl.LOCK_NB)
    except OSError:
        sys.exit("Kurgu oynatıcısı zaten açık.")
    app = QApplication(sys.argv)
    o = Kurgu(float(sys.argv[1]) if len(sys.argv) > 1 else 0)
    sys.exit(app.exec())
