import datetime
import eyed3
import glob
import os
import wx
import wx.media

from ObjectListView import ObjectListView, ColumnDefn


class Mp3:

    def __init__(self, metadata):
        self.artist = ''
        self.album = ''
        self.title = ''
        self.year = ''
        self.path = ''
        now = datetime.datetime.now()
        year = now.strftime("%Y")

        # Attempt to extract MP3 tags
        if not isinstance(metadata.tag, type(None)):
            metadata.tag.artist = self.normalize_mp3(
                metadata.tag.artist)
            self.artist = metadata.tag.artist
            metadata.tag.album = self.normalize_mp3(
                metadata.tag.album)
            self.album = metadata.tag.album
            metadata.tag.title = self.normalize_mp3(
                metadata.tag.title)
            self.title = metadata.tag.title
            if hasattr(metadata.tag, 'best_release_date'):
                if not isinstance(
                    metadata.tag.best_release_date, type(None)):
                    self.year = self.normalize_mp3(
                        metadata.tag.best_release_date.year)
                else:
                    metadata.tag.release_date = year
                    self.year = self.normalize_mp3(
                        metadata.tag.best_release_date.year)
        else:
            tag = metadata.initTag()
            tag.release_date = year
            tag.artist = 'Unknown'
            tag.album = 'Unknown'
            tag.title = 'Unknown'
        
        self.path = metadata.path
        self.id3 = metadata
        self.update()

    def normalize_mp3(self, tag):
        try:
            if tag is not None:
                return tag
            else:
                return 'Unknown'
        except:
            return 'Unknown'

    def update(self):
        self.artist = self.id3.tag.artist
        self.album = self.id3.tag.album
        self.title = self.id3.tag.title
        self.year = self.id3.tag.best_release_date.year

class Mp3PlayerPanel(wx.Panel):
    def __init__(self, parent):
        super().__init__(parent)
        self.current_volume = 50
        sp = wx.StandardPaths.Get()
        self.current_folder = sp.GetDocumentsDir()
        self.current_song = None
        self.mp3s = []
        
        self.create_widgets()
        self.create_menu()
        self.timer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.on_playback_update)
    
    def create_widgets(self):
        try:
            self.media_ctrl = wx.media.MediaCtrl(self, style=wx.SIMPLE_BORDER,
                                                 szBackend="")
            if not self.media_ctrl:
                raise NotImplementedError
        except NotImplementedError:
            self.Destroy()
            raise
        self.Bind(wx.media.EVT_MEDIA_LOADED, self.on_media_loaded)
        
        # Create playback slider
        self.playback_slider = wx.Slider(self, size=wx.DefaultSize)
        self.Bind(wx.EVT_SLIDER, self.on_seek, self.playback_slider)
        
        self.mp3_olv = ObjectListView(
            self, style=wx.LC_REPORT | wx.SUNKEN_BORDER)
        self.mp3_olv.SetEmptyListMsg("No Mp3s Found")
        self.update_mp3_info()
                
        # Create sizers
        main_sizer = wx.BoxSizer(wx.VERTICAL)
        hSizer = wx.BoxSizer(wx.HORIZONTAL)
        audio_sizer = self.create_audio_controls()
                
        # Layout widgets
        main_sizer.Add(self.playback_slider, 0, wx.ALL|wx.EXPAND, 5)
        hSizer.Add(audio_sizer, 0, wx.ALL|wx.CENTER, 5)
        main_sizer.Add(hSizer)
        main_sizer.Add(self.mp3_olv, 1, wx.ALL | wx.EXPAND, 5)
        
        self.SetSizer(main_sizer)
        self.Layout()
        
    def create_audio_controls(self):
        """
        Builds the audio bar controls
        """
        audio_bar_sizer = wx.BoxSizer(wx.HORIZONTAL)
        
        self.previous_btn = wx.Button(self, label='Prev')
        self.previous_btn.Bind(wx.EVT_BUTTON, self.on_skip)
        audio_bar_sizer.Add(self.previous_btn, 0, wx.LEFT, 3)
    
        # Create play/pause toggle button
        self.play_pause_btn = wx.Button(self, label='Play')
        self.play_pause_btn.Enable(False)
        self.play_pause_btn.Bind(wx.EVT_BUTTON, self.on_play)
        audio_bar_sizer.Add(self.play_pause_btn, 0, wx.LEFT, 3)
    
        # Create stop button
        self.stop_button = wx.Button(self, label='Stop')
        self.stop_button.Bind(wx.EVT_BUTTON, self.on_stop)
        audio_bar_sizer.Add(self.stop_button, 0, wx.LEFT, 3)
        
        # Create next button
        self.next_button = wx.Button(self, label='Next')
        self.next_button.Bind(wx.EVT_BUTTON, self.on_skip)
        audio_bar_sizer.Add(self.next_button, 0, wx.LEFT, 3)
    
        return audio_bar_sizer
    
    def create_menu(self):
        """
        Creates a menu
        """
        frame = self.GetParent()
        menubar = wx.MenuBar()
    
        fileMenu = wx.Menu()
        open_file_menu_item = fileMenu.Append(wx.ID_ANY, "&Open", "Open a File")
        menubar.Append(fileMenu, '&File')
        frame.SetMenuBar(menubar)
        frame.Bind(wx.EVT_MENU, self.on_browse, open_file_menu_item)
    
    def add_mp3(self, path):
        id3 = eyed3.load(path)
        mp3_obj = Mp3(id3)
        self.mp3s.append(mp3_obj)
    
    def load_mp3s(self, path):
        if self.mp3s:
            # clear the current contents
            self.mp3s = []
        
        mp3_paths = glob.glob(path + '/*.mp3')
        for mp3_path in mp3_paths:
            self.add_mp3(mp3_path)
        
        # if mp3s loaded, load the first one
        if self.mp3s:
            self.load_music(self.mp3s[0].path)
        
        self.update_mp3_info()
        
    def load_music(self, music_file):
        """
        Load the music into the MediaCtrl or display an error dialog
        if the user tries to load an unsupported file type
        """
        if not self.media_ctrl.Load(music_file):
            wx.MessageBox(f"Unable to load {music_file}: Unsupported format?",
                          "ERROR",
                          wx.ICON_ERROR | wx.OK)
            self.play_pause_btn.Disable()
        else:
            self.media_ctrl.SetInitialSize()
            self.GetSizer().Layout()
            self.playback_slider.SetRange(0, self.media_ctrl.Length())
            self.play_pause_btn.Enable()
            
    def play_music(self):
        self.timer.Start(100)
        if not self.media_ctrl.Play():
            wx.MessageBox("Unable to Play media : Unsupported format?",
                          "ERROR",
                          wx.ICON_ERROR | wx.OK)
        else:
            self.media_ctrl.SetInitialSize()
            self.GetSizer().Layout()
            self.playback_slider.SetRange(0, self.media_ctrl.Length())
            self.play_pause_btn.SetLabel('Pause')
            selected = self.mp3_olv.GetSelectedObject()
            if selected:
                self.current_song = selected
            else:
                self.mp3_olv.Select(0)
                self.current_song = self.mp3s[0]
        
    def on_play(self, event):
        btn = event.GetEventObject()
        if btn.GetLabel() == 'Pause':
            self.on_pause()
            return 
        
        self.play_music()
        event.Skip()
    
    def on_media_loaded(self, event):
        self.play_pause_btn.Enable()
    
    def on_stop(self, event):
        self.timer.Stop()
        self.play_pause_btn.SetLabel('Play')
        self.playback_slider.SetValue(0)
        self.media_ctrl.Stop()
        
    def on_pause(self):
        self.media_ctrl.Pause()
        self.play_pause_btn.SetLabel('Play')
        
    def on_skip(self, event):
        btn = event.GetEventObject()
        self.on_stop(event='')
        pos = 0
        selection = self.mp3_olv.GetSelectedObject()
        if selection:
            pos = self.mp3s.index(selection)
            
        if btn.Label == 'Prev':
            if pos == 0:
                pos = len(self.mp3s) - 1
            else:
                pos -= 1
        else:
            if pos + 1 == len(self.mp3s):
                pos = 0
            else:
                pos += 1
        
        self.load_music(self.mp3s[pos].path)
        self.mp3_olv.SelectObject(self.mp3s[pos])
        self.play_music()
        
    def on_seek(self, event):
        offset = self.playback_slider.GetValue()
        self.media_ctrl.Seek(offset)
        
    def on_playback_update(self, event):
        offset = self.media_ctrl.Tell()
        self.playback_slider.SetValue(offset)
    
    def on_browse(self, event):
        """
        Opens file dialog to browse for music
        """
        wildcard = "MP3 (*.mp3)|*.mp3"
        with wx.DirDialog(self, "Choose a directory:",
                          style=wx.DD_DEFAULT_STYLE,
                          ) as dlg:
            if dlg.ShowModal() == wx.ID_OK:
                path = dlg.GetPath()
                self.current_folder = os.path.dirname(path)
                self.load_mp3s(dlg.GetPath())
                #self.loadMusic(path)
    
    def update_mp3_info(self):
        self.mp3_olv.SetColumns([
            ColumnDefn("Artist", "left", 100, "artist"),
            ColumnDefn("Album", "left", 100, "album"),
            ColumnDefn("Title", "left", 150, "title"),
            ColumnDefn("Year", "left", 100, "year")
        ])
        self.mp3_olv.SetObjects(self.mp3s)
        
class Mp3Frame(wx.Frame):
    def __init__(self):
        super().__init__(None, wx.ID_ANY, "MP3 Player")
        panel = Mp3PlayerPanel(self)
        self.Show()

# Run the program
if __name__ == "__main__":
    app = wx.App()
    frame = Mp3Frame()
    app.MainLoop()