import os
from data.ModelSlot import DiffusionSVCModelSlot, ModelSlot
from voice_changer.DiffusionSVC.inferencer.diffusion_svc_model.diffusion.unit2mel import load_model_vocoder_from_combo
from voice_changer.VoiceChangerParamsManager import VoiceChangerParamsManager
from voice_changer.utils.LoadModelParams import LoadModelParams
from voice_changer.utils.ModelSlotGenerator import ModelSlotGenerator


def get_divisors(n):
    divisors = []
    for i in range(1, int(n**0.5)+1):
        if n % i == 0:
            divisors.append(i)
            if i != n // i:
                divisors.append(n // i)
    return sorted(divisors)


class DiffusionSVCModelSlotGenerator(ModelSlotGenerator):
    @classmethod
    def loadModel(cls, props: LoadModelParams):
        slotInfo: DiffusionSVCModelSlot = DiffusionSVCModelSlot()
        for file in props.files:
            if file.kind == "diffusionSVCModel":
                slotInfo.modelFile = file.name
        slotInfo.defaultTune = 0
        slotInfo.isONNX = slotInfo.modelFile.endswith(".onnx")
        slotInfo.name = os.path.splitext(os.path.basename(slotInfo.modelFile))[0]
        # slotInfo.iconFile = "/assets/icons/noimage.png"
        slotInfo.embChannels = 768
        slotInfo.slotIndex = props.slot

        if slotInfo.isONNX:
            slotInfo = cls._setInfoByONNX(slotInfo)
        else:
            slotInfo = cls._setInfoByPytorch(slotInfo)
        return slotInfo

    @classmethod
    def _setInfoByPytorch(cls, slot: DiffusionSVCModelSlot):
        vcparams = VoiceChangerParamsManager.get_instance().params
        modelPath = os.path.join(vcparams.model_dir, str(slot.slotIndex), os.path.basename(slot.modelFile))

        diff_model, diff_args, naive_model, naive_args = load_model_vocoder_from_combo(modelPath, device="cpu")
        slot.kStepMax = diff_args.model.k_step_max
        slot.nLayers = diff_args.model.n_layers
        slot.nnLayers = naive_args.model.n_layers
        slot.defaultKstep = slot.kStepMax
        divs = get_divisors(slot.defaultKstep)
        slot.defaultSpeedup = divs[-2]
        slot.speakers = {(x+1): f"user{x+1}" for x in range(diff_args.model.n_spk)}
        return slot

    @classmethod
    def _setInfoByONNX(cls, slot: ModelSlot):
        return slot
