from pandas import Series, DataFrame
from hashlib import md5
from masterDBGate import masterDBGate

class myMusicDBIDData:
    def __init__(self, dbID=None):
        self.dbID = None
        self.name = None
        
        self.init = True
        
        
    def dump(self):
        return {"dbID": self.dbID, "name": self.name} #, "init": self.init}
            
        
    def add(self, dbID, name=None):        
        if dbID is None:
            self.dbID = dbID
            self.name = name
            self.init = False
            return
        
        try:
            str(int(dbID))
        except:
            raise ValueError("Cannot set dbID to {0}".format(dbID))
            
        self.init = False
        if str(dbID) == self.dbID:
            return
        self.dbID = str(dbID)
        self.name = name
    
    def setInit(self, initVal):
        self.init = initVal
    
    def getInit(self):
        return self.init
    
    def getID(self):
        return self.dbID
        
    def get(self):
        return (self.dbID,self.name)
            
        
        

class myMusicArtistDBData:
    def __init__(self, primaryKey=None, artistName=None, artistID=None):
        self.primaryKey = primaryKey
        self.artistName = artistName
        self.artistID   = artistID
        self.mdbc       = masterDBGate()
        self.initDBData()
        
        
    ################################################################
    #
    # Dump Data
    #
    ################################################################
    def dump(self):
        dumpData = {"primaryKey": self.primaryKey, "artistName": self.artistName, "artistID": self.artistID}
        dumpData["dbData"] = {db: dbdata.dump() for db,dbdata in self.dbdata.items()}
        return dumpData
        
        
    ################################################################
    #
    # Init Data
    #
    ################################################################
    def initDBData(self):
        self.dbdata = {db: myMusicDBIDData() for db in self.mdbc.getDBs()}
        
    def getInitData(self):
        return {db: dbdata.getInit() for db,dbdata in self.dbdata.items()}
        
    def setDBInitData(self, db, ifUnMatched):
        if self.dbdata.get(db) is not None:
            if ifUnMatched is False:
                self.dbdata[db] = myMusicDBIDData()
            else:
                if self.dbdata[db].getID() is None:
                    self.dbdata[db] = myMusicDBIDData()
                    
    def setDBInitDataForMatched(self, db, forceValue=None):
        if self.dbdata[db].getID() is not None:
            self.dbdata[db].setInit(False)
        else:
            self.dbdata[db].setInit(True)        

        if forceValue is not None:
            self.dbdata[db].setInit(forceValue)
        
    def getDBInitData(self, db):
        if self.dbdata.get(db) is not None:
            return self.dbdata[db].getInit()
        return None

    
    ################################################################
    #
    # Getter Data
    #
    ################################################################
    def getPrimaryKey(self):
        return self.primaryKey
        
    def getArtistName(self):
        return self.artistName
        
    def getArtistID(self):
        return self.artistID
        
    def add(self, db, dbID=None):
        assert self.mdbc.isValid(db), "Invalid DB [{0}]".format(db)
        self.dbdata[db].add(dbID, name=None)
        
    def show(self):
        try:
            print("ArtistName: {0}".format(self.artistName))
        except:
            print("ArtistName: None")
        try:
            print("ArtistID:   {0}".format(self.artistID))
        except:
            print("ArtistID:   None")
            
        print("{0: <20}{1: <8}{2}".format("DB", "Init", "ID"))
        for db,dbIDdata in self.dbdata.items():
            print("{0: <20}{1: <8}{2}".format(db, dbIDdata.getInit(), dbIDdata.getID()))
            
    def getSeries(self):
        s1 = Series({db: dbIDdata.dbID for db,dbIDdata in self.dbdata.items()})
        s2 = Series({"DBMatches": s1.shape[0] - sum(s1.isna())})
        sdata = s1.append(s2)
        return sdata
    
    def getDBData(self, db):
        if self.dbdata.get(db) is not None:
            return self.dbdata[db]
        return None
            
    def getDBID(self, db):
        if self.dbdata.get(db) is not None:
            return self.dbdata[db].dbID
        return None    
    
    def getDict(self):
        dfdata = {db: dbIDdata.dbID for db,dbIDdata in self.dbdata.items()}
        return dfdata
        
    def getDF(self):
        dfdata = DataFrame(Series({db: dbIDdata.dbID for db,dbIDdata in self.dbdata.items()}))
        return dfdata
        
    def get(self):
        return self.dbdata
    
    
class musicDBSourceType:
    def __init__(self, source):
        self.mdbc       = masterDBGate()
        stype = None
        if source in ["Music", "Local"]:
            stype = "local"
        elif self.mdbc.isValid(source):
            stype = "db"
        elif source in ["Master", "Ranked"]:
            stype = "db"
        elif source in ["Top40", "Billboard", "BillboardYE"]:
            stype = "chart"
        elif source in ["Top40Uber", "BillboardUber"]:
            stype = "chart"
        elif source in ["Spotify", "SpotifyViral", "MusicVF", "Wiki", "UDiscover", 
                        "EastAsia", "LatinAmerica", "Russia", "Arab", "RateYourMusic", "RYM",
                        "RYMSong", "RYMAlbum", "RYMList", "RYMSong2", "RYMAlbum2", "RYMList2"]: 
            stype = "chart"
        else:
            print("Could not determine music db source type for db [{0}]".format(source))
            stype = "chart"
            
        self.stype = stype
        
    def isLocal(self):
        return self.stype == "local"
        
    def isDB(self):
        return self.stype == "db"
        
    def isChart(self):
        return self.stype == "chart"
        
    def isTest(self):
        return self.stype == "test"
    
    

class musicDBKey:
    def __init__(self, source):
        self.source  = source
        self.mdbType = musicDBSourceType(source)
        
    def getHash(self, name, extra=[]):
        m = md5()
        m.update(name.encode('utf-8'))
        for value in extra:
            m.update(value.encode('utf-8'))
        retval = m.hexdigest()
        return retval
        
    def getKey(self, artistName=None, artistID=None):
        key = None
        
        if self.mdbType.isLocal() or self.mdbType.isTest():
            if artistName is not None:
                artistID = self.getHash(artistName)
                key = artistID
            elif artistID is not None:
                key = artistID
            else:
                raise ValueError("Can only get local db key with an artist name!")
        elif self.mdbType.isChart():
            if artistName is not None:
                artistID = self.getHash(artistName, extra=[self.source])
                key = artistID
            elif artistID is not None:
                key = artistID
            else:
                raise ValueError("Can only get local db key with an artist name!")
        elif self.mdbType.isDB():
            if artistID is not None:
                key = artistID
            else:
                raise ValueError("Can only get local db key with an artist ID!")
                
        if key is None:
            raise ValueError("Key is NONE!!!")
            
        return key
