import logging

from PyQt6.QtCore import (
    pyqtSignal,
    Qt,
    QModelIndex,
)
from PyQt6.QtWidgets import QAbstractItemView, QMenu

from feeluown.i18n import t
from feeluown.library import SupportsPlaylistAddSong
from feeluown.utils.aio import run_afn, run_fn
from .textlist import TextlistModel, TextlistView


logger = logging.getLogger(__name__)


class PlaylistsModel(TextlistModel):
    def __init__(self, parent):
        super().__init__(parent)
        self._playlists = []
        self._fav_playlists = []

    @property
    def items(self):
        return self._playlists + self._fav_playlists

    def add(self, playlist, is_fav=False):
        if is_fav:
            start = len(self._playlists) + len(self._fav_playlists)
            playlists = self._fav_playlists
        else:
            start = len(self._playlists)
            playlists = self._playlists

        if isinstance(playlist, list):
            _playlists = playlist
        else:
            _playlists = [playlist]
        end = start + len(_playlists)
        self.beginInsertRows(QModelIndex(), start, end)
        playlists.extend(_playlists)
        self.endInsertRows()

    def remove(self, playlist):
        for i, playlist_ in enumerate(self._playlists):
            if playlist_ == playlist:
                self.beginRemoveRows(QModelIndex(), i, i + 1)
                self._playlists.remove(playlist)
                self.endRemoveRows()
                break

        for i, playlist_ in enumerate(self._fav_playlists):
            if playlist_ == playlist:
                start = i + len(self._playlists)
                end = start + 1
                self.beginRemoveRows(QModelIndex(), start, end)
                self._fav_playlists.remove(playlist)
                self.endRemoveRows()
                break

    def clear(self):
        total_length = len(self.items)
        self.beginRemoveRows(QModelIndex(), 0, total_length - 1)
        self._playlists = []
        self._fav_playlists = []
        self.endRemoveRows()

    def flags(self, index):
        if not index.isValid():
            return 0
        flags = Qt.ItemFlag.ItemIsSelectable | Qt.ItemFlag.ItemIsEnabled
        if index.row() < len(self._playlists):
            flags |= Qt.ItemFlag.ItemIsDropEnabled
        return flags

    def data(self, index, role=Qt.ItemDataRole.DisplayRole):
        row = index.row()
        playlist = self.items[row]
        if role == Qt.ItemDataRole.DisplayRole:
            if row < len(self._playlists):
                flag = "♬ "
            else:
                flag = "★ "
            return flag + playlist.name
        return super().data(index, role)


class PlaylistsView(TextlistView):
    """Playlist list view

    This view will display all items; in theory there will be no scroll bar and
    it does not accept scroll events

    .. versiondeprecated:: 3.9
    """

    show_playlist = pyqtSignal([object])
    remove_playlist = pyqtSignal([object])

    def __init__(self, parent):
        super().__init__(parent)

        self.setDragDropMode(QAbstractItemView.DragDropMode.DropOnly)
        self.clicked.connect(self._on_clicked)

    def _on_clicked(self, index):
        playlist = index.data(role=Qt.ItemDataRole.UserRole)
        self.show_playlist.emit(playlist)

    def contextMenuEvent(self, event):
        indexes = self.selectionModel().selectedIndexes()
        if len(indexes) != 1:
            return

        playlist = self.model().data(indexes[0], Qt.ItemDataRole.UserRole)
        menu = QMenu()
        action = menu.addAction(t("track-list-remove"))
        action.triggered.connect(lambda: self.remove_playlist.emit(playlist))
        menu.exec(event.globalPos())

    def dropEvent(self, e):
        mimedata = e.mimeData()
        song = mimedata.model
        index = self.indexAt(e.position().toPoint())
        playlist = index.data(Qt.ItemDataRole.UserRole)
        self._results[index.row] = (index, None)
        self.viewport().update()

        async def do():
            is_success = False
            app = self.parent().parent()._app  # type: ignore[attr-defined]
            try:
                provider = app.library.get(playlist.source)
                if isinstance(provider, SupportsPlaylistAddSong):
                    is_success = await run_fn(
                        provider.playlist_add_song, playlist, song
                    )
            except Exception:  # noqa, to avoid crash.
                logger.exception("add song to playlist failed")
                is_success = False
            app.show_msg(
                t("playlist-add-track", status="succ" if is_success else "fail")
            )
            self._results[index.row] = (index, is_success)
            self.viewport().update()
            self._result_timer.start(2000)

        run_afn(do)
        e.accept()

    def dragMoveEvent(self, e):
        mimedata = e.mimeData()
        song = mimedata.model
        index = self.indexAt(e.position().toPoint())
        playlist = index.data(Qt.ItemDataRole.UserRole)
        if song.source == playlist.source:
            e.accept()
            return
        e.ignore()

    def dragEnterEvent(self, e):
        mimedata = e.mimeData()
        if mimedata.hasFormat("fuo-model/x-song"):
            e.accept()
            return
        e.ignore()
