"""Ana uygulama penceresi — tüm bileşenleri birbirine bağlar."""
from __future__ import annotations
from pathlib import Path
from datetime import datetime
from typing import Optional

from PySide6.QtCore import Qt, QTimer
from PySide6.QtGui import QIcon, QAction
from PySide6.QtWidgets import (
    QMainWindow, QWidget, QHBoxLayout, QVBoxLayout, QSplitter, QTabWidget,
    QFileDialog, QMessageBox, QStatusBar, QLabel,
)

from model import Proje, Sahne, TumAyarlar
from pipeline import LTXClient, ACEStepClient, VideoIslemHatti, SesIslemHatti, ffmpeg_yardimci
from servis import BackendYonetici

from .tema import QSS
from .bilesen import SolPanel, VideoSekmesi, SesSekmesi, LogPaneli


KOK_DIZIN = Path(__file__).resolve().parent.parent
VARSAYILAN_CIKIS = KOK_DIZIN.parent / "output"


class AnaPencere(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("FikoYT Video Stüdyosu")
        self.resize(1500, 950)
        self.setStyleSheet(QSS)

        # ── Model ──
        self.proje = Proje()
        self.proje.ayarlar = TumAyarlar()

        # ── Servisler ──
        self.ltx_client = LTXClient()
        self.ace_client = ACEStepClient(api_url=self.proje.ayarlar.ses.api_url)
        self.backend = BackendYonetici(self.ltx_client, self.ace_client, self)

        # Çalışan worker'lar
        self._video_worker: Optional[VideoIslemHatti] = None
        self._ses_worker: Optional[SesIslemHatti] = None

        # ── UI ──
        self._ui_kur()
        self._menu_kur()
        self._statusbar_kur()
        self._baglantilari_kur()

        # Başlangıç proje görünümü
        self.video_sek.sahneleri_yenile()
        self.sol.proje_bilgisini_guncelle(self.proje.ad, self.proje.proje_dosyasi)

        # Backend izlemeyi başlat
        self.backend.basla()

        # FFmpeg kontrolü
        if not ffmpeg_yardimci.ffmpeg_var_mi():
            self.log.log_ekle("hata", "FFmpeg PATH'te bulunamadı. Ses/video işlemleri başarısız olabilir.")
        else:
            self.log.log_ekle("basari", "FFmpeg hazır.")

    # ------------------------------------------------------------------ UI
    def _ui_kur(self) -> None:
        kok = QWidget()
        self.setCentralWidget(kok)

        ana_layout = QHBoxLayout(kok)
        ana_layout.setContentsMargins(0, 0, 0, 0)
        ana_layout.setSpacing(0)

        self.splitter = QSplitter(Qt.Orientation.Horizontal)

        # Sol panel
        self.sol = SolPanel()
        self.splitter.addWidget(self.sol)

        # Sağ: sekmeler + log
        sag_sarmak = QWidget()
        sag_l = QVBoxLayout(sag_sarmak)
        sag_l.setContentsMargins(5, 10, 10, 10)
        sag_l.setSpacing(8)

        self.sekmeler = QTabWidget()
        self.video_sek = VideoSekmesi(self.proje)
        self.ses_sek = SesSekmesi(self.proje.ayarlar.ses)
        self.sekmeler.addTab(self.video_sek, "🎬 Video")
        self.sekmeler.addTab(self.ses_sek, "🎵 Ses / Şarkı (ACE-Step)")
        sag_l.addWidget(self.sekmeler, 2)

        self.log = LogPaneli()
        sag_l.addWidget(self.log, 1)

        self.splitter.addWidget(sag_sarmak)
        self.splitter.setSizes([360, 1140])
        self.splitter.setCollapsible(0, False)
        self.splitter.setCollapsible(1, False)

        ana_layout.addWidget(self.splitter)

    def _menu_kur(self) -> None:
        mb = self.menuBar()

        dosya = mb.addMenu("&Dosya")

        yeni = QAction("Yeni Proje", self)
        yeni.setShortcut("Ctrl+N")
        yeni.triggered.connect(self._proje_yeni)
        dosya.addAction(yeni)

        ac = QAction("Proje Aç...", self)
        ac.setShortcut("Ctrl+O")
        ac.triggered.connect(self._proje_ac)
        dosya.addAction(ac)

        kaydet = QAction("Kaydet", self)
        kaydet.setShortcut("Ctrl+S")
        kaydet.triggered.connect(self._proje_kaydet)
        dosya.addAction(kaydet)

        fk = QAction("Farklı Kaydet...", self)
        fk.setShortcut("Ctrl+Shift+S")
        fk.triggered.connect(self._proje_farkli_kaydet)
        dosya.addAction(fk)

        dosya.addSeparator()
        cik = QAction("Çıkış", self)
        cik.triggered.connect(self.close)
        dosya.addAction(cik)

        yardim = mb.addMenu("&Yardım")
        hakkinda = QAction("Hakkında", self)
        hakkinda.triggered.connect(self._hakkinda)
        yardim.addAction(hakkinda)

    def _statusbar_kur(self) -> None:
        sb = QStatusBar()
        self.setStatusBar(sb)
        self.durum_etiket = QLabel("Hazır")
        sb.addWidget(self.durum_etiket)

    # --------------------------------------------------------- BAĞLANTILAR
    def _baglantilari_kur(self) -> None:
        # Sol panel
        self.sol.ses_degisti.connect(self._kaynak_ses_secildi)
        self.sol.gorsel_degisti.connect(self._kaynak_gorsel_secildi)
        self.sol.face_kaynak_degisti.connect(self._face_kaynak_secildi)
        self.sol.proje_yeni.connect(self._proje_yeni)
        self.sol.proje_ac.connect(self._proje_ac)
        self.sol.proje_kaydet.connect(self._proje_kaydet)
        self.sol.proje_farkli_kaydet.connect(self._proje_farkli_kaydet)
        self.sol.ltx_baslat.connect(self.backend.ltx_baslat)
        self.sol.ace_baslat.connect(self.backend.ace_baslat)

        # Video sekmesi
        self.video_sek.proje_degisti.connect(self._proje_degisti)
        self.video_sek.uretim_istendi.connect(self._video_uret)
        self.video_sek.iptal_istendi.connect(self._video_iptal)
        self.video_sek.birlestirme_istendi.connect(self._birlestir)
        self.video_sek.otomatik_sahne_uret.connect(self._otomatik_sahne_olustur)

        # Ses sekmesi
        self.ses_sek.uret_istendi.connect(self._ses_uret)
        self.ses_sek.iptal_istendi.connect(self._ses_iptal)
        self.ses_sek.videoya_aktar_istendi.connect(self._ses_videoya_aktar)

        # Backend
        self.backend.ltx_durumu.connect(self.sol.ltx_durumu_guncelle)
        self.backend.ace_durumu.connect(self.sol.ace_durumu_guncelle)
        self.backend.log.connect(self.log.log_ekle)

    # --------------------------------------------------------- KAYNAK DOSYA
    def _kaynak_ses_secildi(self, yol: str) -> None:
        self.proje.kaynak_ses = yol
        if yol:
            self.log.log_ekle("bilgi", f"Kaynak ses seçildi: {Path(yol).name}")
            try:
                sure = ffmpeg_yardimci.ses_suresi(yol)
                self.durum_etiket.setText(f"Ses: {sure:.1f}s")
            except Exception:
                pass

    def _kaynak_gorsel_secildi(self, yol: str) -> None:
        self.proje.kaynak_gorsel = yol
        # İlk sahnenin giriş görselini güncelle
        if self.proje.sahneler and not self.proje.sahneler[0].giris_gorsel:
            self.proje.sahneler[0].giris_gorsel = yol
            self.video_sek.sahneleri_yenile()
        if yol:
            self.log.log_ekle("bilgi", f"Kaynak görsel seçildi: {Path(yol).name}")

    def _face_kaynak_secildi(self, yol: str) -> None:
        self.proje.ayarlar.video.face_swap_kaynak = yol
        self.proje.ayarlar.video.face_swap_aktif = bool(yol)
        if yol:
            self.log.log_ekle("bilgi", f"Face-swap yüzü: {Path(yol).name}")

    def _proje_degisti(self) -> None:
        self.sol.proje_bilgisini_guncelle(self.proje.ad, self.proje.proje_dosyasi)

    # ----------------------------------------------------- PROJE İŞLEMLERİ
    def _proje_yeni(self) -> None:
        self.proje = Proje()
        self.video_sek.proje = self.proje
        self.ses_sek.ayar = self.proje.ayarlar.ses
        self.video_sek.sahneleri_yenile()
        self.sol.proje_bilgisini_guncelle(self.proje.ad, "")
        self.sol.ses_sec.yolu_ayarla("")
        self.sol.gorsel_sec.yolu_ayarla("")
        self.sol.face_sec.yolu_ayarla("")
        self.log.log_ekle("bilgi", "Yeni proje oluşturuldu.")

    def _proje_ac(self) -> None:
        yol, _ = QFileDialog.getOpenFileName(
            self, "Proje aç", str(VARSAYILAN_CIKIS), "FikoYT Proje (*.fiko-video.json *.json)"
        )
        if not yol:
            return
        try:
            self.proje = Proje.yukle(yol)
            self.video_sek.proje = self.proje
            self.ses_sek.ayar = self.proje.ayarlar.ses
            self.video_sek.sahneleri_yenile()
            self.sol.proje_bilgisini_guncelle(self.proje.ad, yol)
            self.sol.ses_sec.yolu_ayarla(self.proje.kaynak_ses)
            self.sol.gorsel_sec.yolu_ayarla(self.proje.kaynak_gorsel)
            self.sol.face_sec.yolu_ayarla(self.proje.ayarlar.video.face_swap_kaynak)
            self.log.log_ekle("basari", f"Proje yüklendi: {yol}")
        except Exception as e:
            QMessageBox.critical(self, "Hata", f"Proje açılamadı:\n{e}")
            self.log.log_ekle("hata", f"Proje yükleme hatası: {e}")

    def _proje_kaydet(self) -> None:
        if not self.proje.proje_dosyasi:
            self._proje_farkli_kaydet()
            return
        try:
            self.proje.kaydet()
            self.log.log_ekle("basari", f"Proje kaydedildi: {self.proje.proje_dosyasi}")
        except Exception as e:
            self.log.log_ekle("hata", f"Kaydetme hatası: {e}")

    def _proje_farkli_kaydet(self) -> None:
        varsayilan = self.proje.proje_dosyasi or str(
            VARSAYILAN_CIKIS / f"{self.proje.ad}.fiko-video.json"
        )
        yol, _ = QFileDialog.getSaveFileName(
            self, "Projeyi kaydet", varsayilan, "FikoYT Proje (*.fiko-video.json)"
        )
        if not yol:
            return
        try:
            self.proje.kaydet(yol)
            self.sol.proje_bilgisini_guncelle(self.proje.ad, yol)
            self.log.log_ekle("basari", f"Proje kaydedildi: {yol}")
        except Exception as e:
            self.log.log_ekle("hata", f"Kaydetme hatası: {e}")

    # ----------------------------------------------------- OTOMATİK SAHNE
    def _otomatik_sahne_olustur(self, segment_sure: int) -> None:
        if not self.proje.kaynak_ses or not Path(self.proje.kaynak_ses).exists():
            QMessageBox.warning(self, "Uyarı", "Önce kaynak ses dosyası seçin.")
            return
        try:
            toplam = ffmpeg_yardimci.ses_suresi(self.proje.kaynak_ses)
        except Exception as e:
            QMessageBox.critical(self, "Hata", f"Ses süresi alınamadı: {e}")
            return

        cevap = QMessageBox.question(
            self, "Sahneleri yeniden oluştur?",
            "Mevcut sahneler silinip ses segmentlerine göre yeniden oluşturulacak. Devam?",
        )
        if cevap != QMessageBox.StandardButton.Yes:
            return

        # Ses segment dizini
        ts = datetime.now().strftime("%Y%m%d_%H%M%S")
        ses_dir = VARSAYILAN_CIKIS / f"proje_{ts}" / "ses_segmentler"
        try:
            segmentler = ffmpeg_yardimci.sesi_segmentlere_bol(
                self.proje.kaynak_ses, ses_dir, segment_sure
            )
        except Exception as e:
            QMessageBox.critical(self, "Hata", f"Ses bölünemedi: {e}")
            return

        self.proje.sahneler.clear()
        for i, (ses_yol, bas, bit, sure) in enumerate(segmentler):
            s = Sahne(
                prompt=self.proje.ayarlar.video.global_prompt,
                sure=int(sure),
                ses_yolu=str(ses_yol),
                guidance_scale=self.proje.ayarlar.video.guidance_scale,
                steps=self.proje.ayarlar.video.steps,
            )
            if i == 0 and self.proje.kaynak_gorsel:
                s.giris_gorsel = self.proje.kaynak_gorsel
            self.proje.sahne_ekle(s)

        self.video_sek.sahneleri_yenile()
        self.log.log_ekle("basari", f"{len(segmentler)} sahne oluşturuldu (ses bölündü).")
        self.durum_etiket.setText(f"{len(segmentler)} sahne hazır")

    # --------------------------------------------------------- VIDEO ÜRETİM
    def _calisma_dizini(self) -> Path:
        if self.proje.ayarlar.uygulama.video_uretim_dizini:
            d = Path(self.proje.ayarlar.uygulama.video_uretim_dizini)
        else:
            ts = datetime.now().strftime("%Y%m%d_%H%M%S")
            ad_temiz = "".join(c if c.isalnum() or c in "-_" else "_" for c in self.proje.ad)
            d = VARSAYILAN_CIKIS / f"{ad_temiz}_{ts}"
        d.mkdir(parents=True, exist_ok=True)
        return d

    def _video_uret(self, sadece_idler: list) -> None:
        if self._video_worker and self._video_worker.isRunning():
            QMessageBox.warning(self, "Uyarı", "Zaten bir üretim sürüyor.")
            return
        if not self.proje.sahneler:
            QMessageBox.warning(self, "Uyarı", "Önce sahne oluşturun.")
            return

        dizin = self._calisma_dizini()
        self.proje.ayarlar.uygulama.video_uretim_dizini = str(dizin)

        self._video_worker = VideoIslemHatti(
            proje=self.proje,
            client=self.ltx_client,
            calisma_dizini=dizin,
            sadece_sahne_idleri=sadece_idler or None,
            otomatik_birlestir=not bool(sadece_idler),  # tek sahne üretiminde birleştirme
            ses_ekle=True,
        )
        self._video_worker.log.connect(self.log.log_ekle)
        self._video_worker.ilerleme.connect(self.video_sek.ilerleme_guncelle)
        self._video_worker.sahne_guncellendi.connect(self.video_sek.sahne_yenile)
        self._video_worker.hata.connect(lambda m: self.video_sek.uretim_modu(False))
        self._video_worker.tamamlandi.connect(self._video_tamamlandi)
        self._video_worker.finished.connect(lambda: self.video_sek.uretim_modu(False))

        self.video_sek.uretim_modu(True)
        self._video_worker.start()

    def _video_iptal(self) -> None:
        if self._video_worker and self._video_worker.isRunning():
            self._video_worker.iptal_et()

    def _video_tamamlandi(self, cikis: str) -> None:
        if cikis:
            self.log.log_ekle("basari", f"Nihai video: {cikis}")
            self.durum_etiket.setText(f"Çıkış: {cikis}")
            self.video_sek.nihai_video_yukle(cikis)

    def _birlestir(self) -> None:
        """Mevcut başarılı segmentleri birleştirip sesi ekle."""
        basarilar = [s for s in self.proje.sahneler if s.durum == "tamamlandi" and s.cikis_video]
        if not basarilar:
            QMessageBox.warning(self, "Uyarı", "Birleştirilecek başarılı sahne yok.")
            return
        dizin = self._calisma_dizini()
        ham = dizin / "birlesmis_ham.mp4"
        import shutil
        if len(basarilar) == 1:
            shutil.copy2(basarilar[0].cikis_video, ham)
        else:
            if not ffmpeg_yardimci.videolari_birlestir([s.cikis_video for s in basarilar], ham):
                self.log.log_ekle("hata", "Birleştirme başarısız.")
                return

        cikis = dizin / f"{self.proje.ad}_nihai.mp4"
        if self.proje.kaynak_ses and Path(self.proje.kaynak_ses).exists():
            if ffmpeg_yardimci.videoya_ses_ekle(ham, self.proje.kaynak_ses, cikis):
                self.proje.cikis_video = str(cikis)
                self.log.log_ekle("basari", f"Nihai video (sesli): {cikis}")
                return
        shutil.copy2(ham, cikis)
        self.proje.cikis_video = str(cikis)
        self.log.log_ekle("basari", f"Nihai video: {cikis}")

    # ---------------------------------------------------------- SES ÜRETİM
    def _ses_uret(self) -> None:
        if self._ses_worker and self._ses_worker.isRunning():
            QMessageBox.warning(self, "Uyarı", "Zaten bir ses üretimi sürüyor.")
            return
        self.ace_client.api_url = self.proje.ayarlar.ses.api_url
        self.ace_client.api_key = self.proje.ayarlar.uygulama.ace_api_key

        ts = datetime.now().strftime("%Y%m%d_%H%M%S")
        hedef = VARSAYILAN_CIKIS / "ace-step" / f"uretim_{ts}.mp3"
        hedef.parent.mkdir(parents=True, exist_ok=True)

        self._ses_worker = SesIslemHatti(self.ace_client, self.proje.ayarlar.ses, hedef)
        self._ses_worker.log.connect(self.log.log_ekle)
        self._ses_worker.ilerleme.connect(self.ses_sek.ilerleme_guncelle)
        self._ses_worker.tamamlandi.connect(self.ses_sek.uretim_bitti)
        self._ses_worker.hata.connect(self.ses_sek.uretim_hatali)

        self.ses_sek.uretim_modu(True)
        self._ses_worker.start()

    def _ses_iptal(self) -> None:
        if self._ses_worker and self._ses_worker.isRunning():
            self._ses_worker.iptal_et()
            self._ses_worker.terminate()

    def _ses_videoya_aktar(self, dosya: str) -> None:
        if not dosya or not Path(dosya).exists():
            return
        self.proje.kaynak_ses = dosya
        self.sol.ses_sec.yolu_ayarla(dosya)
        self.sekmeler.setCurrentWidget(self.video_sek)
        self.log.log_ekle("basari", f"ACE-Step üretimi video pipeline'ına aktarıldı: {dosya}")

    # ---------------------------------------------------------------- MENÜ
    def _hakkinda(self) -> None:
        QMessageBox.information(
            self, "Hakkında",
            "FikoYT Video Stüdyosu\n\n"
            "LTX Desktop + ACE-Step entegreli sahne-bazlı video üretim istasyonu.\n"
            "Her sahnenin prompt, süre, seed, guidance, steps ve face-swap ayarları bağımsızdır.",
        )

    def closeEvent(self, e) -> None:
        self.backend.dur()
        super().closeEvent(e)
