# coding:utf-8
from PySide6.QtCore import Qt, Signal, QSize, QPropertyAnimation, QPoint
from PySide6.QtGui import QPixmap, QPainter, QColor
from PySide6.QtWidgets import QWidget, QGraphicsOpacityEffect, QHBoxLayout, QVBoxLayout

from ..common.icon import FluentIcon
from ..common.style_sheet import isDarkTheme, FluentStyleSheet
from ..components.widgets.button import TransparentToolButton
from ..components.widgets.tool_tip import ToolTipFilter
from ..components.widgets.slider import Slider
from ..components.widgets.label import CaptionLabel
from ..components.widgets.flyout import Flyout, FlyoutViewBase, PullUpFlyoutAnimationManager
from .media_player import MediaPlayer, MediaPlayerBase


class MediaPlayBarButton(TransparentToolButton):
    """ Media play bar button """

    def _postInit(self):
        super()._postInit()
        self.installEventFilter(ToolTipFilter(self, 1000))
        self.setFixedSize(30, 30)
        self.setIconSize(QSize(16, 16))


class PlayButton(MediaPlayBarButton):
    """ Play button """

    def _postInit(self):
        super()._postInit()
        self.setIconSize(QSize(14, 14))
        self.setPlay(False)

    def setPlay(self, isPlay: bool):
        if isPlay:
            self.setIcon(FluentIcon.PAUSE_BOLD)
            self.setToolTip(self.tr('Pause'))
        else:
            self.setIcon(FluentIcon.PLAY_SOLID)
            self.setToolTip(self.tr('Play'))


class VolumeView(FlyoutViewBase):
    """ Volume view """

    def __init__(self, parent=None):
        super().__init__(parent)
        self.muteButton = MediaPlayBarButton(FluentIcon.VOLUME, self)
        self.volumeSlider = Slider(Qt.Horizontal, self)
        self.volumeLabel = CaptionLabel('30', self)

        self.volumeSlider.setRange(0, 100)
        self.volumeSlider.setFixedWidth(208)
        self.setFixedSize(295, 64)

        h = self.height()
        self.muteButton.move(10, h//2-self.muteButton.height()//2)
        self.volumeSlider.move(45, 21)

    def setMuted(self, isMute: bool):
        if isMute:
            self.muteButton.setIcon(FluentIcon.MUTE)
            self.muteButton.setToolTip(self.tr('Unmute'))
        else:
            self.muteButton.setIcon(FluentIcon.VOLUME)
            self.muteButton.setToolTip(self.tr('Mute'))

    def setVolume(self, volume: int):
        self.volumeSlider.setValue(volume)

        self.volumeLabel.setNum(volume)
        self.volumeLabel.adjustSize()

        tr = self.volumeLabel.fontMetrics().boundingRect(str(volume))
        self.volumeLabel.move(self.width() - 20 - tr.width(), self.height()//2 - tr.height()//2)

    def paintEvent(self, e):
        painter = QPainter(self)
        painter.setRenderHints(QPainter.Antialiasing)

        if isDarkTheme():
            painter.setBrush(QColor(46, 46, 46))
            painter.setPen(QColor(0, 0, 0, 20))
        else:
            painter.setBrush(QColor(248, 248, 248))
            painter.setPen(QColor(0, 0, 0, 10))

        painter.drawRoundedRect(self.rect().adjusted(1, 1, -1, -1), 8, 8)


class VolumeButton(MediaPlayBarButton):
    """ Volume button """

    volumeChanged = Signal(int)
    mutedChanged = Signal(bool)

    def _postInit(self):
        super()._postInit()
        self.volumeView = VolumeView(self)
        self.volumeFlyout = Flyout(self.volumeView, self.window(), False)
        self.setMuted(False)

        self.volumeFlyout.hide()
        self.volumeView.muteButton.clicked.connect(lambda: self.mutedChanged.emit(not self.isMuted))
        self.volumeView.volumeSlider.valueChanged.connect(self.volumeChanged)
        self.clicked.connect(self._showVolumeFlyout)

    def setMuted(self, isMute: bool):
        self.isMuted = isMute
        self.volumeView.setMuted(isMute)

        if isMute:
            self.setIcon(FluentIcon.MUTE)
        else:
            self.setIcon(FluentIcon.VOLUME)

    def setVolume(self, volume: int):
        self.volumeView.setVolume(volume)

    def _showVolumeFlyout(self):
        if self.volumeFlyout.isVisible():
            return

        pos = PullUpFlyoutAnimationManager(self.volumeFlyout).position(self)
        self.volumeFlyout.exec(pos)



class MediaPlayBarBase(QWidget):
    """ Play bar base class """

    def __init__(self, parent=None):
        super().__init__(parent=parent)
        self.player = None  # type: MediaPlayerBase

        self.playButton = PlayButton(self)
        self.volumeButton = VolumeButton(self)
        self.progressSlider = Slider(Qt.Horizontal, self)

        self.opacityEffect = QGraphicsOpacityEffect(self)
        self.opacityAni = QPropertyAnimation(self.opacityEffect, b'opacity')
        self.opacityEffect.setOpacity(1)
        self.opacityAni.setDuration(250)

        self.setGraphicsEffect(self.opacityEffect)
        FluentStyleSheet.MEDIA_PLAYER.apply(self)

        self.playButton.clicked.connect(self.togglePlayState)

    def setMediaPlayer(self, player: MediaPlayerBase):
        """ set media player """
        self.player = player

        self.player.durationChanged.connect(self.progressSlider.setMaximum)
        self.player.positionChanged.connect(self._onPositionChanged)
        self.player.mediaStatusChanged.connect(self._onMediaStatusChanged)
        self.player.volumeChanged.connect(self.volumeButton.setVolume)
        self.player.mutedChanged.connect(self.volumeButton.setMuted)

        # don't use valueChanged, otherwise the sound will be interupted
        self.progressSlider.sliderMoved.connect(self.player.setPosition)
        self.progressSlider.clicked.connect(self.player.setPosition)
        self.volumeButton.volumeChanged.connect(self.player.setVolume)
        self.volumeButton.mutedChanged.connect(self.player.setMuted)

        self.player.setVolume(30)

    def fadeIn(self):
        self.opacityAni.setStartValue(self.opacityEffect.opacity())
        self.opacityAni.setEndValue(1)
        self.opacityAni.start()

    def fadeOut(self):
        self.opacityAni.setStartValue(self.opacityEffect.opacity())
        self.opacityAni.setEndValue(0)
        self.opacityAni.start()

    def play(self):
        self.player.play()

    def pause(self):
        self.player.pause()

    def stop(self):
        self.player.stop()

    def setVolume(self, volume: int):
        """ Sets the volume of player """
        self.player.setVolume(volume)

    def setPosition(self, position: int):
        """ Sets the position of media in ms """
        self.player.setPosition(position)

    def _onPositionChanged(self, position: int):
        self.progressSlider.setValue(position)

    def _onMediaStatusChanged(self, status):
        self.playButton.setPlay(self.player.isPlaying())

    def togglePlayState(self):
        """ toggle the play state of media player """
        if self.player.isPlaying():
            self.player.pause()
        else:
            self.player.play()

        self.playButton.setPlay(self.player.isPlaying())

    def paintEvent(self, e):
        painter = QPainter(self)
        painter.setRenderHints(QPainter.Antialiasing)

        if isDarkTheme():
            painter.setBrush(QColor(46, 46, 46))
            painter.setPen(QColor(0, 0, 0, 20))
        else:
            painter.setBrush(QColor(248, 248, 248))
            painter.setPen(QColor(0, 0, 0, 10))

        painter.drawRoundedRect(self.rect().adjusted(1, 1, -1, -1), 8, 8)



class SimpleMediaPlayBar(MediaPlayBarBase):
    """ simple media play bar """

    def __init__(self, parent=None):
        super().__init__(parent)
        self.hBoxLayout = QHBoxLayout(self)

        self.hBoxLayout.setContentsMargins(10, 4, 10, 4)
        self.hBoxLayout.setSpacing(6)
        self.hBoxLayout.addWidget(self.playButton, 0, Qt.AlignLeft)
        self.hBoxLayout.addWidget(self.progressSlider, 1)
        self.hBoxLayout.addWidget(self.volumeButton, 0)

        self.setFixedHeight(48)
        self.setMediaPlayer(MediaPlayer(self))

    def addButton(self, button: MediaPlayBarButton):
        """ add button to the right side of play bar """
        self.hBoxLayout.addWidget(button, 0)


class StandardMediaPlayBar(MediaPlayBarBase):
    """ Standard media play bar """

    def __init__(self, parent=None):
        super().__init__(parent)
        self.vBoxLayout = QVBoxLayout(self)
        self.timeLayout = QHBoxLayout()
        self.buttonLayout = QHBoxLayout()
        self.leftButtonContainer = QWidget()
        self.centerButtonContainer = QWidget()
        self.rightButtonContainer = QWidget()
        self.leftButtonLayout = QHBoxLayout(self.leftButtonContainer)
        self.centerButtonLayout = QHBoxLayout(self.centerButtonContainer)
        self.rightButtonLayout = QHBoxLayout(self.rightButtonContainer)

        self.skipBackButton = MediaPlayBarButton(FluentIcon.SKIP_BACK, self)
        self.skipForwardButton = MediaPlayBarButton(FluentIcon.SKIP_FORWARD, self)

        self.currentTimeLabel = CaptionLabel('0:00:00', self)
        self.remainTimeLabel = CaptionLabel('0:00:00', self)

        self.__initWidgets()

    def __initWidgets(self):
        self.setFixedHeight(102)
        self.vBoxLayout.setSpacing(6)
        self.vBoxLayout.setContentsMargins(5, 9, 5, 9)
        self.vBoxLayout.addWidget(self.progressSlider, 1, Qt.AlignTop)

        self.vBoxLayout.addLayout(self.timeLayout)
        self.timeLayout.setContentsMargins(10, 0, 10, 0)
        self.timeLayout.addWidget(self.currentTimeLabel, 0, Qt.AlignLeft)
        self.timeLayout.addWidget(self.remainTimeLabel, 0, Qt.AlignRight)

        self.vBoxLayout.addStretch(1)
        self.vBoxLayout.addLayout(self.buttonLayout, 1)
        self.buttonLayout.setContentsMargins(0, 0, 0, 0)
        self.leftButtonLayout.setContentsMargins(4, 0, 0, 0)
        self.centerButtonLayout.setContentsMargins(0, 0, 0, 0)
        self.rightButtonLayout.setContentsMargins(0, 0, 4, 0)

        self.leftButtonLayout.addWidget(self.volumeButton, 0, Qt.AlignLeft)
        self.centerButtonLayout.addWidget(self.skipBackButton)
        self.centerButtonLayout.addWidget(self.playButton)
        self.centerButtonLayout.addWidget(self.skipForwardButton)

        self.buttonLayout.addWidget(self.leftButtonContainer, 0, Qt.AlignLeft)
        self.buttonLayout.addWidget(self.centerButtonContainer, 0, Qt.AlignHCenter)
        self.buttonLayout.addWidget(self.rightButtonContainer, 0, Qt.AlignRight)

        self.setMediaPlayer(MediaPlayer(self))

        self.skipBackButton.clicked.connect(lambda: self.skipBack(10000))
        self.skipForwardButton.clicked.connect(lambda: self.skipForward(30000))

    def skipBack(self, ms: int):
        """ Back up for specified milliseconds """
        self.player.setPosition(self.player.position()-ms)

    def skipForward(self, ms: int):
        """ Fast forward specified milliseconds """
        self.player.setPosition(self.player.position()+ms)

    def _onPositionChanged(self, position: int):
        super()._onPositionChanged(position)
        self.currentTimeLabel.setText(self._formatTime(position))
        self.remainTimeLabel.setText(self._formatTime(self.player.duration() - position))

    def _formatTime(self, time: int):
        time = int(time / 1000)
        s = time % 60
        m = int(time / 60) % 60
        h = int(time / 3600)
        return f'{h}:{m:02}:{s:02}'