"""
library_panel.py — Musikbibliotek med søgning og drag-and-drop til danseliste.
"""

from PyQt6.QtWidgets import (
    QWidget, QVBoxLayout, QListWidget, QListWidgetItem,
    QLineEdit, QLabel, QHBoxLayout, QPushButton,
    QFrame, QSlider, QCheckBox,
    QAbstractItemView, QStyledItemDelegate,
)
from PyQt6.QtCore import Qt, pyqtSignal, QTimer, QMimeData, QByteArray, QRect
from PyQt6.QtGui import QColor, QDrag, QPainter, QBrush, QPen, QFont


class DanseButtonDelegate(QStyledItemDelegate):
    """Tegner en orange 'Danse' label i højre side af hvert list-item."""

    BTN_W = 54
    BTN_H = 22
    BTN_MARGIN = 8

    def paint(self, painter: QPainter, option, index):
        super().paint(painter, option, index)
        rect = option.rect
        btn_rect = QRect(
            rect.right() - self.BTN_W - self.BTN_MARGIN,
            rect.top() + (rect.height() - self.BTN_H) // 2,
            self.BTN_W,
            self.BTN_H,
        )
        painter.save()
        painter.setRenderHint(QPainter.RenderHint.Antialiasing)
        painter.setBrush(QBrush(QColor("#e8a020")))
        painter.setPen(Qt.PenStyle.NoPen)
        painter.drawRoundedRect(btn_rect, 4, 4)
        painter.setPen(QPen(QColor("#111111")))
        font = QFont()
        font.setPointSize(8)
        font.setBold(True)
        painter.setFont(font)
        painter.drawText(btn_rect, Qt.AlignmentFlag.AlignCenter, "Danse")
        painter.restore()


class DraggableLibraryList(QListWidget):
    """QListWidget med drag, dobbeltklik og klik på højre side for dans-tags."""

    danse_clicked = __import__('PyQt6.QtCore', fromlist=['pyqtSignal']).pyqtSignal(dict)

    def __init__(self, parent=None):
        super().__init__(parent)
        self.setDragEnabled(True)
        self.setDragDropMode(QAbstractItemView.DragDropMode.DragOnly)
        self.setDefaultDropAction(Qt.DropAction.CopyAction)

    def mousePressEvent(self, event):
        if event.button() == Qt.MouseButton.LeftButton:
            item = self.itemAt(event.pos())
            if item and event.pos().x() > self.viewport().width() - 75:
                song = item.data(Qt.ItemDataRole.UserRole)
                if song:
                    self.danse_clicked.emit(song)
                    return
        super().mousePressEvent(event)

    def mouseDoubleClickEvent(self, event):
        if event.button() == Qt.MouseButton.LeftButton:
            item = self.itemAt(event.pos())
            if item:
                # Dobbeltklik i højre 75px = Danse, ellers song_selected
                if event.pos().x() > self.viewport().width() - 75:
                    song = item.data(Qt.ItemDataRole.UserRole)
                    if song:
                        self.danse_clicked.emit(song)
                    return
        super().mouseDoubleClickEvent(event)

    def startDrag(self, supported_actions):
        item = self.currentItem()
        if not item:
            return
        song = item.data(Qt.ItemDataRole.UserRole)
        if not song:
            return

        import json
        data = json.dumps(song).encode("utf-8")

        mime = QMimeData()
        mime.setData("application/x-linedance-song", QByteArray(data))
        mime.setText(song.get("title", ""))

        drag = QDrag(self)
        drag.setMimeData(mime)
        drag.exec(Qt.DropAction.CopyAction)


class LibraryPanel(QWidget):
    song_selected       = pyqtSignal(dict)
    add_to_playlist     = pyqtSignal(dict)
    scan_requested      = pyqtSignal()
    sync_requested      = pyqtSignal()
    edit_tags_requested = pyqtSignal(dict)
    send_mail_requested = pyqtSignal(dict)

    def __init__(self, parent=None):
        super().__init__(parent)
        self._all_songs: list[dict] = []
        self._filtered:  list[dict] = []
        self._bpm_scan_running = False
        self._search_timer = QTimer(self)
        self._search_timer.setSingleShot(True)
        self._search_timer.setInterval(150)
        self._search_timer.timeout.connect(self._do_search)
        self._build_ui()

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

        # Header
        header = QHBoxLayout()
        header.setContentsMargins(10, 6, 10, 6)
        lbl = QLabel("BIBLIOTEK")
        lbl.setObjectName("section_title")
        header.addWidget(lbl)
        header.addStretch()

        btn_refresh = QPushButton("↻  Opdater")
        btn_refresh.setFixedHeight(28)
        btn_refresh.setToolTip("Opdater bibliotek fra database")
        btn_refresh.clicked.connect(self._refresh_library)
        header.addWidget(btn_refresh)

        btn_manage = QPushButton("⚙  Mapper")
        btn_manage.setFixedHeight(28)
        btn_manage.setToolTip("Tilføj, fjern og scan musikbiblioteker")
        btn_manage.clicked.connect(self._manage_libraries)
        header.addWidget(btn_manage)
        layout.addLayout(header)

        # Søgefelt + checkbox
        search_row = QHBoxLayout()
        search_row.setSpacing(6)
        self._search = QLineEdit()
        self._search.setPlaceholderText("Søg i titel, artist, album, dans...")
        self._search.textChanged.connect(self._on_search_changed)
        search_row.addWidget(self._search)
        from PyQt6.QtWidgets import QCheckBox
        self._chk_alt = QCheckBox("Inkl. alt.")
        self._chk_alt.setToolTip("Søg også i alternativ-danse")
        self._chk_alt.setChecked(False)
        self._chk_alt.toggled.connect(self._on_search_changed)
        search_row.addWidget(self._chk_alt)
        layout.addLayout(search_row)

        # Resultat-tæller + drag-hint
        hint_row = QHBoxLayout()
        hint_row.setContentsMargins(8, 2, 8, 2)
        self._count_label = QLabel("0 sange")
        self._count_label.setObjectName("result_count")
        hint_row.addWidget(self._count_label)
        hint_row.addStretch()
        drag_hint = QLabel("træk til danseliste →")
        drag_hint.setObjectName("result_count")
        hint_row.addWidget(drag_hint)
        layout.addLayout(hint_row)

        # Liste — draggable
        self._list = DraggableLibraryList()
        self._list.setObjectName("library_list")
        self._list.itemDoubleClicked.connect(self._on_double_click)
        self._list.danse_clicked.connect(self.edit_tags_requested)
        self._list.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
        self._list.customContextMenuRequested.connect(self._show_context_menu)
        self._list.setItemDelegate(DanseButtonDelegate(self._list))
        layout.addWidget(self._list)

        # Preview-afspiller bar
        self._preview_bar = self._build_preview_bar()
        self._preview_bar.setVisible(False)
        layout.addWidget(self._preview_bar)

        # Timer til preview progress opdatering
        self._preview_timer = QTimer(self)
        self._preview_timer.setInterval(200)
        self._preview_timer.timeout.connect(self._update_preview_progress)

    def _build_preview_bar(self) -> QWidget:
        bar = QFrame()
        bar.setObjectName("track_display")
        bar.setFixedHeight(62)
        row = QHBoxLayout(bar)
        row.setContentsMargins(10, 8, 10, 8)
        row.setSpacing(10)

        # Play/pause knap — orange som hoved-afspiller
        self._btn_preview_play = QPushButton("▶")
        self._btn_preview_play.setFixedSize(36, 36)
        self._btn_preview_play.setObjectName("btn_play_small")
        self._btn_preview_play.setToolTip("Afspil / Pause")
        self._btn_preview_play.clicked.connect(self._toggle_preview_playback)
        row.addWidget(self._btn_preview_play)

        # Stop knap
        self._btn_preview_stop = QPushButton("■")
        self._btn_preview_stop.setFixedSize(30, 30)
        self._btn_preview_stop.setObjectName("btn_stop_small")
        self._btn_preview_stop.setToolTip("Stop preview")
        self._btn_preview_stop.clicked.connect(self._stop_preview)
        row.addWidget(self._btn_preview_stop)

        # Titel + progress i midten
        info = QVBoxLayout()
        info.setSpacing(4)
        info.setContentsMargins(0, 0, 0, 0)

        self._lbl_preview_title = QLabel("—")
        self._lbl_preview_title.setObjectName("track_meta")
        info.addWidget(self._lbl_preview_title)

        self._preview_progress = QSlider(Qt.Orientation.Horizontal)
        self._preview_progress.setRange(0, 1000)
        self._preview_progress.sliderMoved.connect(self._seek_preview)
        info.addWidget(self._preview_progress)
        row.addLayout(info, stretch=1)

        # Tid
        self._lbl_preview_time = QLabel("0:00")
        self._lbl_preview_time.setObjectName("track_meta")
        self._lbl_preview_time.setFixedWidth(70)
        self._lbl_preview_time.setAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter)
        row.addWidget(self._lbl_preview_time)

        # Volumen
        self._preview_vol = QSlider(Qt.Orientation.Horizontal)
        self._preview_vol.setRange(0, 100)
        self._preview_vol.setValue(78)
        self._preview_vol.setFixedWidth(70)
        self._preview_vol.setToolTip("Volumen preview")
        self._preview_vol.valueChanged.connect(self._on_preview_volume)
        row.addWidget(self._preview_vol)

        return bar

    # ── Scanning ──────────────────────────────────────────────────────────────

    def _on_scan_clicked(self):
        self.scan_requested.emit()

    def _on_sync_clicked(self):
        self._btn_sync.setText("⇅  ...")
        self._btn_sync.setEnabled(False)
        self.sync_requested.emit()
        QTimer.singleShot(3000, lambda: (
            self._btn_sync.setText("⇅  Sync"),
            self._btn_sync.setEnabled(True),
        ))

    def set_scanning(self, scanning: bool, status_text: str = ""):
        pass  # Status vises i statuslinjen

    def update_scan_status(self, text: str):
        pass  # Status vises i statuslinjen

    # ── Sange ─────────────────────────────────────────────────────────────────

    def load_songs(self, songs: list[dict]):
        self._all_songs = songs
        self._do_search()

    # ── Søgning ───────────────────────────────────────────────────────────────

    def _on_search_changed(self):
        self._search_timer.start()

    def _do_search(self):
        q = self._search.text().strip().lower()
        incl_alt = self._chk_alt.isChecked()
        self._filtered = [
            s for s in self._all_songs if self._matches(s, q, incl_alt)
        ] if q else list(self._all_songs)
        total = len(self._all_songs)
        found = len(self._filtered)
        q_text = self._search.text().strip()
        self._count_label.setText(
            f"{found} resultat{'er' if found != 1 else ''} for \"{q_text}\"" if q_text
            else f"{total} sang{'e' if total != 1 else ''}"
        )
        self._render()

    def _matches(self, song: dict, q: str, incl_alt: bool = False) -> bool:
        fields = [
            song.get("title", ""),
            song.get("artist", ""),
            song.get("album", ""),
            song.get("file_format", ""),
        ] + song.get("dances", []) \
          + song.get("dance_choreographers", []) \
          + song.get("dance_levels", [])
        if incl_alt:
            fields += song.get("alt_dances", [])
        return any(q in f.lower() for f in fields if f)

    def _render(self):
        self._list.clear()
        q = self._search.text().strip().lower()
        for song in self._filtered:
            dances      = song.get("dances", [])
            dance_levels = song.get("dance_levels", [])
            missing     = song.get("file_missing", False)

            dance_parts = []
            choreos = song.get("dance_choreographers", [])
            for i, d in enumerate(dances):
                lvl = dance_levels[i] if i < len(dance_levels) else ""
                choreo = choreos[i] if i < len(choreos) else ""
                part = f"{d} / {lvl}" if lvl else d
                if choreo:
                    part += f" · {choreo}"
                dance_parts.append(part)
            dance_str = "  ·  " + "  |  ".join(dance_parts) if dance_parts else ""

            prefix = "⚠  " if missing else ""
            bpm    = song.get("bpm", 0)
            bpm_str = f"{bpm} BPM" if bpm else "? BPM"
            line1  = prefix + song.get("title", "—")
            line2  = f"  {song.get('artist','—')}  ·  {bpm_str}  ·  {song.get('file_format','').upper()}{dance_str}"

            item = QListWidgetItem(f"{line1}\n{line2}")
            item.setData(Qt.ItemDataRole.UserRole, song)
            item.setSizeHint(__import__('PyQt6.QtCore', fromlist=['QSize']).QSize(0, 52))
            if missing:
                item.setForeground(QColor("#5a6070"))
            elif q and any(q in d.lower() for d in dances):
                item.setForeground(QColor("#e8a020"))
            self._list.addItem(item)

    def _start_bulk_bpm_scan(self):
        """Start BPM-analyse på alle sange uden BPM i baggrundstråd med lav prioritet."""
        if self._bpm_scan_running:
            return
        songs_without_bpm = [s for s in self._all_songs
                             if not s.get("bpm") and not s.get("file_missing")]
        if not songs_without_bpm:
            self._btn_bpm_scan.setText("♩  Alle har BPM")
            return

        self._bpm_scan_running = True
        self._btn_bpm_scan.setText(f"♩  Scanner 0/{len(songs_without_bpm)}...")
        self._btn_bpm_scan.setEnabled(False)

        from PyQt6.QtCore import QThread, pyqtSignal as _sig

        class BulkBpmWorker(QThread):
            progress = _sig(int, int, str)  # done, total, title
            finished = _sig()

            def __init__(self, songs):
                super().__init__()
                self._songs = songs

            def run(self):
                from local.tag_reader import analyze_and_save_bpm
                total = len(self._songs)
                for i, song in enumerate(self._songs, start=1):
                    if self.isInterruptionRequested():
                        break
                    try:
                        bpm = analyze_and_save_bpm(song["local_path"], song["id"])
                        if bpm:
                            song["bpm"] = int(round(bpm))
                    except Exception:
                        pass
                    self.progress.emit(i, total, song.get("title", ""))
                self.finished.emit()

        self._bulk_bpm_worker = BulkBpmWorker(songs_without_bpm)

        def on_progress(done, total, title):
            self._btn_bpm_scan.setText(f"♩  {done}/{total}...")
            # Opdater sangen i listen
            for s in self._all_songs:
                if s.get("title") == title and s.get("bpm"):
                    break
            self._do_search()

        def on_finished():
            self._bpm_scan_running = False
            self._btn_bpm_scan.setEnabled(True)
            self._btn_bpm_scan.setText("♩  BPM alle")
            self._do_search()

        self._bulk_bpm_worker.progress.connect(on_progress)
        self._bulk_bpm_worker.finished.connect(on_finished)
        self._bulk_bpm_worker.start()
        self._bulk_bpm_worker.setPriority(QThread.Priority.LowestPriority)

    # ── Handlinger ────────────────────────────────────────────────────────────

    def _show_context_menu(self, pos):
        from PyQt6.QtWidgets import QMenu
        item = self._list.itemAt(pos)
        if not item:
            return
        song = item.data(Qt.ItemDataRole.UserRole)
        if not song:
            return
        menu = QMenu(self)
        act_add     = menu.addAction("Tilføj til danseliste")
        act_play    = menu.addAction("Afspil")
        # Preview kun hvis preview player er sat op
        is_previewing = (
            hasattr(self, "_preview_player") and
            self._preview_player and
            self._preview_player.is_playing()
        )
        act_preview = menu.addAction(
            "⏹  Stop preview" if is_previewing else "▶  Preview (høretelefoner)"
        )
        menu.addSeparator()
        act_tags   = menu.addAction("✎  Rediger dans-tags...")
        act_info   = menu.addAction("ℹ  Dans-info...")
        act_bpm    = menu.addAction("♩  Analysér BPM")
        menu.addSeparator()
        send_menu  = menu.addMenu("Send til")
        act_mail   = send_menu.addAction("✉  Send som mail")
        action = menu.exec(self._list.mapToGlobal(pos))
        if action == act_add:
            self.add_to_playlist.emit(song)
        elif action == act_play:
            self.song_selected.emit(song)
        elif action == act_preview:
            self._toggle_preview(song)
        elif action == act_tags:
            self.edit_tags_requested.emit(song)
        elif action == act_info:
            from ui.dance_info_dialog import DanceInfoDialog
            dlg = DanceInfoDialog(song, parent=self.window())
            dlg.exec()
        elif action == act_bpm:
            self._analyze_bpm(song)
        elif action == act_mail:
            self.send_mail_requested.emit(song)

    def set_preview_player(self, preview_player):
        """Sæt preview-afspilleren fra main_window."""
        self._preview_player = preview_player

    def _on_double_click(self, item: QListWidgetItem):
        song = item.data(Qt.ItemDataRole.UserRole)
        if song:
            self._start_preview(song)

    def _start_preview(self, song: dict):
        if not hasattr(self, "_preview_player") or not self._preview_player:
            self.song_selected.emit(song)
            return
        path = song.get("local_path", "")
        if not path:
            return
        self._preview_song = song
        self._preview_player.play(path)
        title = song.get("title", "—")
        artist = song.get("artist", "")
        self._lbl_preview_title.setText(f"{title}  ·  {artist}")
        self._btn_preview_play.setText("⏸")
        self._preview_bar.setVisible(True)
        self._preview_timer.start()

    def _toggle_preview_playback(self):
        if not hasattr(self, "_preview_player") or not self._preview_player:
            return
        if self._preview_player.is_playing():
            self._preview_player.pause()
            self._btn_preview_play.setText("▶")
        else:
            self._preview_player.resume()
            self._btn_preview_play.setText("⏸")

    def _stop_preview(self):
        if hasattr(self, "_preview_player") and self._preview_player:
            self._preview_player.stop()
        self._preview_timer.stop()
        self._preview_bar.setVisible(False)
        self._btn_preview_play.setText("▶")

    def _seek_preview(self, value: int):
        if hasattr(self, "_preview_player") and self._preview_player:
            self._preview_player.seek(value / 1000.0)

    def _on_preview_volume(self, value: int):
        if hasattr(self, "_preview_player") and self._preview_player:
            self._preview_player.set_volume(value)

    def _update_preview_progress(self):
        if not hasattr(self, "_preview_player") or not self._preview_player:
            return
        if not self._preview_player.is_playing():
            self._btn_preview_play.setText("▶")
            return
        pos = self._preview_player.get_position()
        cur = self._preview_player.get_time()
        dur = self._preview_player.get_duration()
        self._preview_progress.setValue(int(pos * 1000))
        def fmt(s): return f"{s//60}:{s%60:02d}"
        self._lbl_preview_time.setText(f"{fmt(cur)} / {fmt(dur)}")

    def _toggle_preview(self, song: dict):
        """Start/stop preview af en sang."""
        if not hasattr(self, "_preview_player") or not self._preview_player:
            return
        if self._preview_player.is_playing():
            self._stop_preview()
        else:
            self._start_preview(song)

    def _analyze_bpm(self, song: dict):
        """Analysér BPM i baggrundstråd og opdater biblioteket."""
        path = song.get("local_path", "")
        song_id = song.get("id", "")
        if not path or not song_id:
            return
        from PyQt6.QtCore import QThread, pyqtSignal as _sig

        class BpmWorker(QThread):
            done = _sig(float)
            def __init__(self, p, sid):
                super().__init__()
                self._p, self._sid = p, sid
            def run(self):
                from local.tag_reader import analyze_and_save_bpm
                bpm = analyze_and_save_bpm(self._p, self._sid)
                if bpm:
                    self.done.emit(bpm)

        self._bpm_worker = BpmWorker(path, song_id)

        def on_bpm_done(bpm):
            # Opdater sangen i _all_songs listen direkte
            for s in self._all_songs:
                if s.get("id") == song_id:
                    s["bpm"] = int(round(bpm))
                    break
            self._do_search()

        self._bpm_worker.done.connect(on_bpm_done)
        self._bpm_worker.start()

    def _refresh_library(self):
        """Genindlæs bibliotek fra database."""
        mw = self.window()
        if hasattr(mw, "_reload_library"):
            mw._reload_library()

    def _manage_libraries(self):
        from ui.library_manager import LibraryManagerDialog
        from local.local_db import DB_PATH
        dialog = LibraryManagerDialog(db_path=str(DB_PATH), parent=self.window())
        dialog.libraries_changed.connect(self._on_libraries_changed)
        dialog.exec()
        # Reload øjeblikkeligt når dialog lukkes
        mw = self.window()
        if hasattr(mw, "_reload_library"):
            mw._reload_library()
        # Start scanning
        if hasattr(mw, "start_background_scan"):
            QTimer.singleShot(1000, mw.start_background_scan)

    def _on_libraries_changed(self):
        """Kaldes ved tilføj/fjern — reload øjeblikkeligt."""
        mw = self.window()
        if hasattr(mw, "_reload_library"):
            mw._reload_library()

    def _add_folder(self):
        from PyQt6.QtWidgets import QFileDialog
        folder = QFileDialog.getExistingDirectory(self, "Vælg musikmappe")
        if folder:
            mw = self.window()
            if hasattr(mw, "add_library_path"):
                mw.add_library_path(folder)
