from typing import Optional

from PyQt6.QtCore import QEvent, Qt
from PyQt6.QtWidgets import QDialog, QListWidgetItem

from classes import MusicMusterSignals
from dbconfig import scoped_session
from helpers import (
    get_relative_date,
    ms_to_mmss,
)
from models import Settings, Tracks
from ui.dlg_TrackSelect_ui import Ui_Dialog  # type: ignore


class TrackSelectDialog(QDialog):
    """Select track from database"""

    def __init__(
        self,
        session: scoped_session,
        new_row_number: int,
        playlist_id: int,
        add_to_header: Optional[bool] = False,
        *args,
        **kwargs,
    ) -> None:
        """
        Subclassed QDialog to manage track selection
        """

        super().__init__(*args, **kwargs)
        self.session = session
        self.new_row_number = new_row_number
        self.playlist_id = playlist_id
        self.add_to_header = add_to_header
        self.ui = Ui_Dialog()
        self.ui.setupUi(self)
        self.ui.btnAdd.clicked.connect(self.add_selected)
        self.ui.btnAddClose.clicked.connect(self.add_selected_and_close)
        self.ui.btnClose.clicked.connect(self.close)
        self.ui.matchList.itemDoubleClicked.connect(self.add_selected)
        self.ui.matchList.itemSelectionChanged.connect(self.selection_changed)
        self.ui.radioTitle.toggled.connect(self.title_artist_toggle)
        self.ui.searchString.textEdited.connect(self.chars_typed)
        self.track: Optional[Tracks] = None
        self.signals = MusicMusterSignals()

        record = Settings.get_int_settings(self.session, "dbdialog_width")
        width = record.f_int or 800
        record = Settings.get_int_settings(self.session, "dbdialog_height")
        height = record.f_int or 600
        self.resize(width, height)

    def add_selected(self) -> None:
        """Handle Add button"""

        track = None

        if self.ui.matchList.selectedItems():
            item = self.ui.matchList.currentItem()
            if item:
                track = item.data(Qt.ItemDataRole.UserRole)

        note = self.ui.txtNote.text()

        if not note and not track:
            return

        self.ui.txtNote.clear()
        self.select_searchtext()

        track_id = None
        if track:
            track_id = track.id
        if self.add_to_header:
            self.signals.add_track_to_header_signal.emit(
                self.playlist_id, self.new_row_number, track_id
            )
        else:
            self.signals.add_track_to_playlist_signal.emit(
                self.playlist_id, self.new_row_number, track_id, note
            )

    def add_selected_and_close(self) -> None:
        """Handle Add and Close button"""

        self.add_selected()
        self.accept()

    def chars_typed(self, s: str) -> None:
        """Handle text typed in search box"""

        self.ui.matchList.clear()
        if len(s) > 0:
            if self.ui.radioTitle.isChecked():
                matches = Tracks.search_titles(self.session, "%" + s)
            else:
                matches = Tracks.search_artists(self.session, "%" + s)
            if matches:
                for track in matches:
                    last_played = None
                    last_playdate = max(
                        track.playdates, key=lambda p: p.lastplayed, default=None
                    )
                    if last_playdate:
                        last_played = last_playdate.lastplayed
                    t = QListWidgetItem()
                    track_text = (
                        f"{track.title} - {track.artist} "
                        f"[{ms_to_mmss(track.duration)}] "
                        f"({get_relative_date(last_played)})"
                    )
                    t.setText(track_text)
                    t.setData(Qt.ItemDataRole.UserRole, track)
                    self.ui.matchList.addItem(t)

    def closeEvent(self, event: Optional[QEvent]) -> None:
        """
        Override close and save dialog coordinates
        """

        if not event:
            return

        record = Settings.get_int_settings(self.session, "dbdialog_height")
        if record.f_int != self.height():
            record.update(self.session, {"f_int": self.height()})

        record = Settings.get_int_settings(self.session, "dbdialog_width")
        if record.f_int != self.width():
            record.update(self.session, {"f_int": self.width()})

        event.accept()

    def keyPressEvent(self, event):
        """
        Clear selection on ESC if there is one
        """

        if event.key() == Qt.Key.Key_Escape:
            if self.ui.matchList.selectedItems():
                self.ui.matchList.clearSelection()
                return

        super(TrackSelectDialog, self).keyPressEvent(event)

    def select_searchtext(self) -> None:
        """Select the searchbox"""

        self.ui.searchString.selectAll()
        self.ui.searchString.setFocus()

    def selection_changed(self) -> None:
        """Display selected track path in dialog box"""

        if not self.ui.matchList.selectedItems():
            return

        item = self.ui.matchList.currentItem()
        track = item.data(Qt.ItemDataRole.UserRole)
        last_playdate = max(track.playdates, key=lambda p: p.lastplayed, default=None)
        if last_playdate:
            last_played = last_playdate.lastplayed
        else:
            last_played = None
        path_text = f"{track.path} ({get_relative_date(last_played)})"

        self.ui.dbPath.setText(path_text)

    def title_artist_toggle(self) -> None:
        """
        Handle switching between searching for artists and searching for
        titles
        """

        # Logic is handled already in chars_typed(), so just call that.
        self.chars_typed(self.ui.searchString.text())
