"""
library_manager.py — Håndter musikmapper.
Tilføj/fjern mapper. BPM-scanning per bibliotek.
Fil-scanning starter automatisk når vinduet lukkes.
"""
import sqlite3
from pathlib import Path

from PyQt6.QtWidgets import (
    QDialog, QVBoxLayout, QHBoxLayout, QLabel,
    QPushButton, QFrame, QMessageBox, QScrollArea, QWidget,
)
from PyQt6.QtCore import Qt, pyqtSignal, QTimer, QThread


class LibraryManagerDialog(QDialog):
    libraries_changed = pyqtSignal()

    def __init__(self, db_path: str, parent=None):
        super().__init__(parent)
        self._db_path = db_path
        self._workers = {}   # library_id → ScanWorker

        self.setWindowTitle("Musikmapper")
        self.setMinimumWidth(600)
        self.setMinimumHeight(300)
        self._build_ui()
        self._load()

    # ── UI ────────────────────────────────────────────────────────────────────

    def _build_ui(self):
        layout = QVBoxLayout(self)
        layout.setContentsMargins(12, 12, 12, 12)
        layout.setSpacing(8)

        lbl = QLabel(
            "Tilføj eller fjern musikmapper. "
            "Fil-scanning starter automatisk når vinduet lukkes."
        )
        lbl.setObjectName("result_count")
        lbl.setWordWrap(True)
        layout.addWidget(lbl)

        # Scrollbart område til biblioteksliste
        scroll = QScrollArea()
        scroll.setWidgetResizable(True)
        scroll.setFrameShape(QFrame.Shape.NoFrame)
        self._scroll_content = QWidget()
        self._libs_layout = QVBoxLayout(self._scroll_content)
        self._libs_layout.setSpacing(6)
        self._libs_layout.addStretch()
        scroll.setWidget(self._scroll_content)
        layout.addWidget(scroll, stretch=1)

        # Knap-række
        btn_row = QHBoxLayout()
        btn_add = QPushButton("＋  Tilføj mappe")
        btn_add.clicked.connect(self._add_folder)
        btn_row.addWidget(btn_add)
        btn_row.addStretch()
        btn_close = QPushButton("Luk")
        btn_close.clicked.connect(self.accept)
        btn_row.addWidget(btn_close)
        layout.addLayout(btn_row)

    def _load(self):
        """Indlæs biblioteker fra DB og vis dem."""
        from PyQt6.QtWidgets import QApplication

        # Ryd eksisterende rækker (ikke stretch)
        while self._libs_layout.count() > 1:
            item = self._libs_layout.takeAt(0)
            if item.widget():
                item.widget().deleteLater()
        QApplication.processEvents()  # Lad Qt rydde op før vi bygger nyt

        try:
            conn = sqlite3.connect(self._db_path)
            conn.row_factory = sqlite3.Row
            libs = conn.execute(
                "SELECT id, path FROM libraries "
                "WHERE is_active=1 ORDER BY path"
            ).fetchall()

            counts = {}
            bpm_missing = {}
            for lib in libs:
                counts[lib["id"]] = conn.execute(
                    "SELECT COUNT(*) FROM files "
                    "WHERE file_missing=0 AND local_path LIKE ?",
                    (lib["path"] + "%",)
                ).fetchone()[0]
                bpm_missing[lib["id"]] = conn.execute(
                    "SELECT COUNT(*) FROM files f "
                    "JOIN songs s ON s.id = f.song_id "
                    "WHERE f.file_missing=0 AND f.local_path LIKE ? "
                    "AND (s.bpm IS NULL OR s.bpm=0)",
                    (lib["path"] + "%",)
                ).fetchone()[0]
            conn.close()

            if not libs:
                lbl = QLabel("Ingen musikmapper tilføjet endnu.")
                lbl.setObjectName("result_count")
                self._libs_layout.insertWidget(0, lbl)
                return

            for i, lib in enumerate(libs):
                row = self._make_lib_row(
                    dict(lib),
                    counts[lib["id"]],
                    bpm_missing[lib["id"]]
                )
                self._libs_layout.insertWidget(i, row)

        except Exception as e:
            lbl = QLabel(f"Fejl: {e}")
            self._libs_layout.insertWidget(0, lbl)

    def _make_lib_row(self, lib: dict, song_count: int,
                      bpm_missing: int) -> QFrame:
        lib_id = lib["id"]
        path   = lib["path"]
        exists = Path(path).exists()
        last   = "—"

        frame = QFrame()
        frame.setObjectName("track_display")
        vbox = QVBoxLayout(frame)
        vbox.setContentsMargins(10, 8, 10, 8)
        vbox.setSpacing(4)

        # Sti
        lbl_path = QLabel(("⚠  " if not exists else "") + path)
        lbl_path.setObjectName("track_title" if exists else "result_count")
        vbox.addWidget(lbl_path)

        # Info
        lbl_info = QLabel(
            f"  {song_count} sange  ·  "
            f"senest scannet: {last}  ·  "
            f"{bpm_missing} uden BPM"
            + ("  ·  ⚠ mappe ikke fundet" if not exists else "")
        )
        lbl_info.setObjectName("result_count")
        vbox.addWidget(lbl_info)

        # Status-label til scanning
        lbl_status = QLabel("")
        lbl_status.setObjectName("result_count")
        lbl_status.hide()
        vbox.addWidget(lbl_status)

        # Knapper
        btn_row = QHBoxLayout()
        btn_row.setSpacing(6)

        btn_bpm = QPushButton(f"♩  BPM manglende ({bpm_missing})")
        btn_bpm.setFixedHeight(30)
        btn_bpm.setEnabled(exists and bpm_missing > 0
                           and lib_id not in self._workers)
        btn_bpm.clicked.connect(
            lambda _, lid=lib_id, p=path, b=btn_bpm, s=lbl_status:
                self._start_bpm(lid, p, False, b, s)
        )
        btn_row.addWidget(btn_bpm)

        btn_bpm_all = QPushButton("♩  BPM alle")
        btn_bpm_all.setFixedHeight(30)
        btn_bpm_all.setEnabled(exists and lib_id not in self._workers)
        btn_bpm_all.clicked.connect(
            lambda _, lid=lib_id, p=path, b=btn_bpm_all, s=lbl_status:
                self._start_bpm(lid, p, True, b, s)
        )
        btn_row.addWidget(btn_bpm_all)

        btn_row.addStretch()

        btn_remove = QPushButton("✕  Fjern")
        btn_remove.setFixedHeight(30)
        btn_remove.clicked.connect(lambda _, l=lib: self._remove_library(l))
        btn_row.addWidget(btn_remove)

        vbox.addLayout(btn_row)
        return frame

    # ── Tilføj / fjern ────────────────────────────────────────────────────────

    def _add_folder(self):
        from PyQt6.QtWidgets import QFileDialog
        folder = QFileDialog.getExistingDirectory(self, "Vælg musikmappe")
        if not folder:
            return
        try:
            conn = sqlite3.connect(self._db_path)
            conn.row_factory = sqlite3.Row

            # Tjek om mappen allerede er aktiv
            existing = conn.execute(
                "SELECT id, is_active FROM libraries WHERE path=?", (folder,)
            ).fetchone()

            if existing:
                if existing["is_active"]:
                    QMessageBox.information(
                        self, "Allerede tilføjet",
                        "Denne mappe er allerede i listen."
                    )
                    conn.close()
                    return
                else:
                    # Reaktiver en tidligere fjernet mappe
                    conn.execute(
                        "UPDATE libraries SET is_active=1 WHERE path=?",
                        (folder,)
                    )
            else:
                conn.execute(
                    "INSERT INTO libraries (path, is_active) VALUES (?, 1)",
                    (folder,)
                )
            conn.commit()
            conn.close()
            self._load()
            self.libraries_changed.emit()
        except Exception as e:
            QMessageBox.warning(self, "Fejl", f"Kunne ikke tilføje: {e}")

    def _remove_library(self, lib: dict):
        reply = QMessageBox.question(
            self, "Fjern mappe",
            f"Fjern:\n{lib['path']}\n\n"
            "Alle sange fra denne mappe slettes fra databasen.\n"
            "Dans-tags og playlister bevares.",
            QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
        )
        if reply != QMessageBox.StandardButton.Yes:
            return

        # Stop evt. BPM-scanning på dette bibliotek
        if lib["id"] in self._workers:
            self._workers[lib["id"]].cancel()
            self._workers.pop(lib["id"], None)

        try:
            conn = sqlite3.connect(self._db_path)
            # Marker filer fra denne mappe som missing
            conn.execute(
                "UPDATE files SET file_missing=1 WHERE local_path LIKE ?",
                (lib["path"] + "%",)
            )
            # Slet selve biblioteks-rækken
            conn.execute(
                "DELETE FROM libraries WHERE id=?", (lib["id"],)
            )
            conn.commit()
            conn.close()
            self._load()
            QTimer.singleShot(300, self.libraries_changed.emit)
        except Exception as e:
            QMessageBox.warning(self, "Fejl", f"Kunne ikke fjerne: {e}")

    # ── BPM-scanning ──────────────────────────────────────────────────────────

    def _start_bpm(self, library_id: int, path: str,
                   scan_all: bool, btn: QPushButton, lbl: QLabel):
        if library_id in self._workers:
            return

        from local.local_db import DB_PATH
        from ui.bpm_worker import BpmScanWorker

        worker = BpmScanWorker(library_id, str(DB_PATH),
                               scan_all=scan_all)

        def on_progress(done, total):
            lbl.setText(f"♩  {done}/{total} analyseret...")
            lbl.show()
            btn.setEnabled(False)

        def on_finished(count):
            lbl.setText(f"✓  {count} analyseret")
            btn.setEnabled(True)
            self._workers.pop(library_id, None)
            QTimer.singleShot(300, self._load)

        worker.progress.connect(on_progress)
        worker.finished.connect(on_finished)
        self._workers[library_id] = worker
        worker.start()
        worker.setPriority(QThread.Priority.LowestPriority)

    # ── Luk ───────────────────────────────────────────────────────────────────

    def closeEvent(self, event):
        for w in list(self._workers.values()):
            w.cancel()
            w.wait(2000)  # Vent max 2 sek på at tråden stopper
        event.accept()