import { useState, useMemo, useEffect } from "react"
import { VoiceChangerServerSetting, ServerInfo, ServerSettingKey, INDEXEDDB_KEY_SERVER, INDEXEDDB_KEY_MODEL_DATA, ClientType, DefaultServerSetting_MMVCv13, DefaultServerSetting_MMVCv15, DefaultServerSetting_so_vits_svc_40v2, DefaultServerSetting_so_vits_svc_40, DefaultServerSetting_so_vits_svc_40_c, DefaultServerSetting_RVC, OnnxExporterInfo, DefaultServerSetting_DDSP_SVC, MAX_MODEL_SLOT_NUM, Framework, MergeModelRequest, VoiceChangerType } from "../const"
import { VoiceChangerClient } from "../VoiceChangerClient"
import { useIndexedDB } from "./useIndexedDB"
import { ModelLoadException } from "../exceptions"


type ModelData = {
    file?: File
    data?: ArrayBuffer
    filename?: string
}

export const ModelAssetName = {
    iconFile: "iconFile"
} as const
export type ModelAssetName = typeof ModelAssetName[keyof typeof ModelAssetName]


export const ModelFileKind = {
    "mmvcv13Config": "mmvcv13Config",
    "mmvcv13Model": "mmvcv13Model",
    "mmvcv15Config": "mmvcv15Config",
    "mmvcv15Model": "mmvcv15Model",

    "soVitsSvc40Config": "soVitsSvc40Config",
    "soVitsSvc40Model": "soVitsSvc40Model",
    "soVitsSvc40Cluster": "soVitsSvc40Cluster",

    "rvcModel": "rvcModel",
    "rvcIndex": "rvcIndex",

    "ddspSvcModel": "ddspSvcModel",
    "ddspSvcModelConfig": "ddspSvcModelConfig",
    "ddspSvcDiffusion": "ddspSvcDiffusion",
    "ddspSvcDiffusionConfig": "ddspSvcDiffusionConfig",

} as const
export type ModelFileKind = typeof ModelFileKind[keyof typeof ModelFileKind]

export type ModelFile = {
    file: File,
    kind: ModelFileKind
    dir: string
}

export type ModelUploadSetting = {
    voiceChangerType: VoiceChangerType,
    slot: number
    isSampleMode: boolean
    sampleId: string | null

    files: ModelFile[]
}
export type ModelFileForServer = Omit<ModelFile, "file"> & {
    name: string,
    kind: ModelFileKind
}
export type ModelUploadSettingForServer = Omit<ModelUploadSetting, "files"> & {
    files: ModelFileForServer[]
}

export type FileUploadSetting = {
    isHalf: boolean
    uploaded: boolean
    defaultTune: number
    defaultIndexRatio: number
    defaultProtect: number
    framework: Framework
    params: string

    mmvcv13Config: ModelData | null
    mmvcv13Model: ModelData | null
    mmvcv15Config: ModelData | null
    mmvcv15Model: ModelData | null
    soVitsSvc40Config: ModelData | null
    soVitsSvc40Model: ModelData | null
    soVitsSvc40Cluster: ModelData | null
    soVitsSvc40v2Config: ModelData | null
    soVitsSvc40v2Model: ModelData | null
    soVitsSvc40v2Cluster: ModelData | null
    rvcModel: ModelData | null
    rvcFeature: ModelData | null
    rvcIndex: ModelData | null

    isSampleMode: boolean
    sampleId: string | null
    rvcIndexDownload: boolean

    ddspSvcModel: ModelData | null
    ddspSvcModelConfig: ModelData | null
    ddspSvcDiffusion: ModelData | null
    ddspSvcDiffusionConfig: ModelData | null

}

export const InitialFileUploadSetting: FileUploadSetting = {
    isHalf: true,
    uploaded: false,
    defaultTune: 0,
    defaultIndexRatio: 1,
    defaultProtect: 0.5,
    framework: Framework.PyTorch,
    params: "{}",

    mmvcv13Config: null,
    mmvcv13Model: null,
    mmvcv15Config: null,
    mmvcv15Model: null,
    soVitsSvc40Config: null,
    soVitsSvc40Model: null,
    soVitsSvc40Cluster: null,
    soVitsSvc40v2Config: null,
    soVitsSvc40v2Model: null,
    soVitsSvc40v2Cluster: null,
    rvcModel: null,
    rvcFeature: null,
    rvcIndex: null,

    isSampleMode: false,
    sampleId: null,
    rvcIndexDownload: true,


    ddspSvcModel: null,
    ddspSvcModelConfig: null,
    ddspSvcDiffusion: null,
    ddspSvcDiffusionConfig: null,
}

type AssetUploadSetting = {
    slot: number
    name: ModelAssetName
    file: string
}

export type UseServerSettingProps = {
    clientType: ClientType | null
    voiceChangerClient: VoiceChangerClient | null
}

export type ServerSettingState = {
    serverSetting: ServerInfo
    updateServerSettings: (setting: ServerInfo) => Promise<void>
    clearSetting: () => Promise<void>
    reloadServerInfo: () => Promise<void>;

    fileUploadSettings: FileUploadSetting[]
    setFileUploadSetting: (slot: number, val: FileUploadSetting) => void
    loadModel: (slot: number) => Promise<void>
    uploadModel: (setting: ModelUploadSetting) => Promise<void>
    uploadProgress: number
    isUploading: boolean

    getOnnx: () => Promise<OnnxExporterInfo>
    mergeModel: (request: MergeModelRequest) => Promise<ServerInfo>
    updateModelDefault: () => Promise<ServerInfo>
    updateModelInfo: (slot: number, key: string, val: string) => Promise<ServerInfo>
    uploadAssets: (slot: number, name: ModelAssetName, file: File) => Promise<void>
}

export const useServerSetting = (props: UseServerSettingProps): ServerSettingState => {
    // const settingRef = useRef<VoiceChangerServerSetting>(DefaultVoiceChangerServerSetting)
    const getDefaultServerSetting = () => {
        if (props.clientType == "MMVCv13") {
            return DefaultServerSetting_MMVCv13
        } else if (props.clientType == "MMVCv15") {
            return DefaultServerSetting_MMVCv15
        } else if (props.clientType == "so-vits-svc-40") {
            return DefaultServerSetting_so_vits_svc_40
        } else if (props.clientType == "so-vits-svc-40_c") {
            console.log("default so_vits_svc_40_c")
            return DefaultServerSetting_so_vits_svc_40_c
        } else if (props.clientType == "so-vits-svc-40v2") {
            return DefaultServerSetting_so_vits_svc_40v2
        } else if (props.clientType == "DDSP-SVC") {
            return DefaultServerSetting_DDSP_SVC
        } else if (props.clientType == "RVC") {
            return DefaultServerSetting_RVC
        } else {
            return DefaultServerSetting_MMVCv15
        }
    }

    const [serverSetting, setServerSetting] = useState<ServerInfo>(getDefaultServerSetting())
    const [fileUploadSettings, setFileUploadSettings] = useState<FileUploadSetting[]>([])
    const { setItem, getItem, removeItem } = useIndexedDB({ clientType: props.clientType })


    // clientTypeが新しく設定されたときに、serverのmodelType動作を変更+設定反映
    useEffect(() => {
        if (!props.voiceChangerClient) return
        if (!props.clientType) return
        const setInitialSetting = async () => {
            // Set Model Type
            await props.voiceChangerClient!.switchModelType(props.clientType!)

            // Load Default (and Cache) and set
            const defaultServerSetting = getDefaultServerSetting()
            const cachedServerSetting = await getItem(INDEXEDDB_KEY_SERVER)
            let initialSetting: ServerInfo
            if (cachedServerSetting) {
                initialSetting = {
                    ...defaultServerSetting, ...cachedServerSetting as ServerInfo,
                    serverAudioStated: 0,
                    inputSampleRate: 48000
                }// sample rateは時限措置
            } else {
                initialSetting = { ...defaultServerSetting }
            }
            setServerSetting(initialSetting)

            // upload setting
            for (let i = 0; i < Object.values(ServerSettingKey).length; i++) {
                const k = Object.values(ServerSettingKey)[i] as keyof VoiceChangerServerSetting
                const v = initialSetting[k]
                if (v) {
                    props.voiceChangerClient!.updateServerSettings(k, "" + v)
                }
            }

            // Load file upload cache
            const loadedFileUploadSettings: FileUploadSetting[] = []
            for (let i = 0; i < MAX_MODEL_SLOT_NUM; i++) {
                const modleKey = `${INDEXEDDB_KEY_MODEL_DATA}_${i}`
                const fileuploadSetting = await getItem(modleKey)
                if (!fileuploadSetting) {
                    loadedFileUploadSettings.push(InitialFileUploadSetting)
                } else {
                    loadedFileUploadSettings.push(fileuploadSetting as FileUploadSetting)
                }
            }
            setFileUploadSettings(loadedFileUploadSettings)


            reloadServerInfo()
        }

        setInitialSetting()

    }, [props.voiceChangerClient, props.clientType])

    //////////////
    // 設定
    /////////////
    const updateServerSettings = useMemo(() => {
        return async (setting: ServerInfo) => {
            if (!props.voiceChangerClient) return
            for (let i = 0; i < Object.values(ServerSettingKey).length; i++) {
                const k = Object.values(ServerSettingKey)[i] as keyof VoiceChangerServerSetting
                const cur_v = serverSetting[k]
                const new_v = setting[k]
                if (cur_v != new_v) {
                    const res = await props.voiceChangerClient.updateServerSettings(k, "" + new_v)
                    if (res.onnxExecutionProviders && res.onnxExecutionProviders.length > 0) {
                        res.onnxExecutionProvider = res.onnxExecutionProviders[0]
                    } else {
                        res.onnxExecutionProvider = "CPUExecutionProvider"
                    }

                    setServerSetting(res)
                    const storeData = { ...res }
                    storeData.recordIO = 0
                    setItem(INDEXEDDB_KEY_SERVER, storeData)
                }
            }
        }
    }, [props.voiceChangerClient, serverSetting])

    const setFileUploadSetting = useMemo(() => {
        return async (slot: number, fileUploadSetting: FileUploadSetting) => {
            fileUploadSetting.uploaded = false
            fileUploadSettings[slot] = fileUploadSetting
            setFileUploadSettings([...fileUploadSettings])
        }
    }, [fileUploadSettings])


    //////////////
    // 操作
    /////////////
    const [uploadProgress, setUploadProgress] = useState<number>(0)
    const [isUploading, setIsUploading] = useState<boolean>(false)

    // (e) モデルアップロード
    const _uploadFile = useMemo(() => {
        return async (modelData: ModelData, onprogress: (progress: number, end: boolean) => void, dir: string = "") => {
            if (!props.voiceChangerClient) return
            const num = await props.voiceChangerClient.uploadFile(modelData.data!, dir + modelData.filename!, onprogress)
            const res = await props.voiceChangerClient.concatUploadedFile(dir + modelData.filename!, num)
            console.log("uploaded", num, res)
        }
    }, [props.voiceChangerClient])

    const _uploadFile2 = useMemo(() => {
        return async (file: File, onprogress: (progress: number, end: boolean) => void, dir: string = "") => {
            if (!props.voiceChangerClient) return
            console.log("uploading..1.", file)
            console.log("uploading..2.", file.name)
            const num = await props.voiceChangerClient.uploadFile2(dir, file, onprogress)
            const res = await props.voiceChangerClient.concatUploadedFile(dir + file.name, num)
            console.log("uploaded", num, res)
        }
    }, [props.voiceChangerClient])

    // 新しいアップローダ
    const uploadModel = useMemo(() => {
        return async (setting: ModelUploadSetting) => {
            if (!props.voiceChangerClient) {
                return
            }

            setUploadProgress(0)
            setIsUploading(true)


            if (setting.isSampleMode == false) {
                const progRate = 1 / setting.files.length
                for (let i = 0; i < setting.files.length; i++) {
                    const progOffset = 100 * i * progRate
                    await _uploadFile2(setting.files[i].file, (progress: number, _end: boolean) => {
                        setUploadProgress(progress * progRate + progOffset)
                    }, setting.files[i].dir)
                }
            }
            const params: ModelUploadSettingForServer = {
                ...setting, files: setting.files.map((f) => { return { name: f.file.name, kind: f.kind, dir: f.dir } })
            }

            const loadPromise = props.voiceChangerClient.loadModel(
                0,
                false,
                JSON.stringify(params),
            )
            await loadPromise

            setUploadProgress(0)
            setIsUploading(false)
            reloadServerInfo()

        }
    }, [props.voiceChangerClient])


    // 古いアップローダ(新GUIへ以降まで、当分残しておく。)
    const loadModel = useMemo(() => {
        return async (slot: number) => {
            const fileUploadSetting = fileUploadSettings[slot]
            console.log("[loadModel]", fileUploadSetting)
            console.log("[loadModel] model:", props.clientType)

            if (fileUploadSetting.isSampleMode == false) {
                if (props.clientType == "MMVCv13") {
                    if (!fileUploadSetting.mmvcv13Config) {
                        throw new ModelLoadException("Config")
                    }
                    if (!fileUploadSetting.mmvcv13Model) {
                        throw new ModelLoadException("Model")
                    }
                } else if (props.clientType == "MMVCv15") {
                    if (!fileUploadSetting.mmvcv15Config) {
                        throw new ModelLoadException("Config")
                    }
                    if (!fileUploadSetting.mmvcv15Model) {
                        throw new ModelLoadException("Model")
                    }
                } else if (props.clientType == "so-vits-svc-40") {
                    if (!fileUploadSetting.soVitsSvc40Config) {
                        throw new ModelLoadException("Config")
                    }
                    if (!fileUploadSetting.soVitsSvc40Model) {
                        throw new ModelLoadException("Model")
                    }
                } else if (props.clientType == "so-vits-svc-40v2") {
                    if (!fileUploadSetting.soVitsSvc40v2Config) {
                        throw new ModelLoadException("Config")
                    }
                    if (!fileUploadSetting.soVitsSvc40v2Model) {
                        throw new ModelLoadException("Model")
                    }
                } else if (props.clientType == "RVC") {
                    if (!fileUploadSetting.rvcModel) {
                        throw new ModelLoadException("Model")
                    }
                } else if (props.clientType == "DDSP-SVC") {
                    if (!fileUploadSetting.ddspSvcModel) {
                        throw new ModelLoadException("DDSP-Model")
                    }
                    if (!fileUploadSetting.ddspSvcModelConfig) {
                        throw new ModelLoadException("DDSP-Config")
                    }
                    if (!fileUploadSetting.ddspSvcDiffusion) {
                        throw new ModelLoadException("Diff-Model")
                    }
                    if (!fileUploadSetting.ddspSvcDiffusionConfig) {
                        throw new ModelLoadException("Diff-Config")
                    }
                } else {
                }
            } else {//Sampleモード
                if (!fileUploadSetting.sampleId) {
                    throw new ModelLoadException("SampleId")
                }
            }


            if (!props.voiceChangerClient) return

            setUploadProgress(0)
            setIsUploading(true)

            // normal models(MMVC13,15, so-vits-svc, RVC)
            const normalModels = [
                fileUploadSetting.mmvcv13Config,
                fileUploadSetting.mmvcv13Model,
                fileUploadSetting.mmvcv15Config,
                fileUploadSetting.mmvcv15Model,
                fileUploadSetting.soVitsSvc40Config,
                fileUploadSetting.soVitsSvc40Model,
                fileUploadSetting.soVitsSvc40Cluster,
                fileUploadSetting.soVitsSvc40v2Config,
                fileUploadSetting.soVitsSvc40v2Model,
                fileUploadSetting.soVitsSvc40v2Cluster,

            ].filter(x => { return x != null }) as ModelData[]
            console.log("[SENDING FILE]", normalModels)
            for (let i = 0; i < normalModels.length; i++) {
                if (!normalModels[i].data) {
                    // const fileSize = normalModels[i].file!.size / 1024 / 1024
                    normalModels[i].data = await normalModels[i].file!.arrayBuffer()
                    normalModels[i].filename = await normalModels[i].file!.name
                }
            }
            if (fileUploadSetting.isSampleMode == false) {
                for (let i = 0; i < normalModels.length; i++) {
                    const progRate = 1 / normalModels.length
                    const progOffset = 100 * i * progRate
                    await _uploadFile(normalModels[i], (progress: number, _end: boolean) => {
                        setUploadProgress(progress * progRate + progOffset)
                    })
                    // await _uploadFile2(normalModels[i].file!, (progress: number, _end: boolean) => {
                    //     setUploadProgress(progress * progRate + progOffset)
                    // })
                }
            }

            // slotModel ローカルキャッシュ無効(RVC)
            const slotModels = [
                fileUploadSetting.rvcModel,
                fileUploadSetting.rvcIndex,

            ].filter(x => { return x != null }) as ModelData[]
            for (let i = 0; i < slotModels.length; i++) {
                if (!slotModels[i].data) {
                    slotModels[i].filename = await slotModels[i].file!.name
                }
            }
            if (fileUploadSetting.isSampleMode == false) {
                for (let i = 0; i < slotModels.length; i++) {
                    const progRate = 1 / slotModels.length
                    const progOffset = 100 * i * progRate
                    await _uploadFile2(slotModels[i].file!, (progress: number, _end: boolean) => {
                        setUploadProgress(progress * progRate + progOffset)
                    })
                }
            }



            // DDSP-SVC (ファイル名(config)が被る可能性があるため、アップロードフォルダを分ける必要がある)
            const ddspSvcModels = [fileUploadSetting.ddspSvcModel, fileUploadSetting.ddspSvcModelConfig, fileUploadSetting.ddspSvcDiffusion, fileUploadSetting.ddspSvcDiffusionConfig].filter(x => { return x != null }) as ModelData[]
            for (let i = 0; i < ddspSvcModels.length; i++) {
                if (!ddspSvcModels[i].data) {
                    ddspSvcModels[i].data = await ddspSvcModels[i].file!.arrayBuffer()
                    ddspSvcModels[i].filename = await ddspSvcModels[i].file!.name
                }
            }
            if (fileUploadSetting.isSampleMode == false) {
                for (let i = 0; i < ddspSvcModels.length; i++) {
                    const progRate = 1 / ddspSvcModels.length
                    const progOffset = 100 * i * progRate
                    const dir = i == 0 || i == 1 ? "ddsp_mod/" : "ddsp_diff/"
                    await _uploadFile(ddspSvcModels[i], (progress: number, _end: boolean) => {
                        setUploadProgress(progress * progRate + progOffset)
                    }, dir)
                }
            }

            // const configFileName = fileUploadSetting.configFile?.filename || "-"
            const params = JSON.stringify({
                defaultTune: fileUploadSetting.defaultTune || 0,
                defaultIndexRatio: fileUploadSetting.defaultIndexRatio || 1,
                defaultProtect: fileUploadSetting.defaultProtect || 0.5,
                sampleId: fileUploadSetting.isSampleMode ? fileUploadSetting.sampleId || "" : "",
                rvcIndexDownload: fileUploadSetting.rvcIndexDownload || false,
                files: fileUploadSetting.isSampleMode ? {} : {
                    mmvcv13Config: props.clientType == "MMVCv13" ? fileUploadSetting.mmvcv13Config?.filename || "" : "",
                    mmvcv13Model: props.clientType == "MMVCv13" ? fileUploadSetting.mmvcv13Model?.filename || "" : "",
                    mmvcv15Config: props.clientType == "MMVCv15" ? fileUploadSetting.mmvcv15Config?.filename || "" : "",
                    mmvcv15Model: props.clientType == "MMVCv15" ? fileUploadSetting.mmvcv15Model?.filename || "" : "",
                    soVitsSvc40Config: props.clientType == "so-vits-svc-40" ? fileUploadSetting.soVitsSvc40Config?.filename || "" : "",
                    soVitsSvc40Model: props.clientType == "so-vits-svc-40" ? fileUploadSetting.soVitsSvc40Model?.filename || "" : "",
                    soVitsSvc40Cluster: props.clientType == "so-vits-svc-40" ? fileUploadSetting.soVitsSvc40Cluster?.filename || "" : "",
                    rvcModel: props.clientType == "RVC" ? fileUploadSetting.rvcModel?.filename || "" : "",
                    rvcIndex: props.clientType == "RVC" ? fileUploadSetting.rvcIndex?.filename || "" : "",
                    rvcFeature: props.clientType == "RVC" ? fileUploadSetting.rvcFeature?.filename || "" : "",

                    ddspSvcModel: props.clientType == "DDSP-SVC" ? fileUploadSetting.ddspSvcModel?.filename ? "ddsp_mod/" + fileUploadSetting.ddspSvcModel?.filename : "" : "",
                    ddspSvcModelConfig: props.clientType == "DDSP-SVC" ? fileUploadSetting.ddspSvcModelConfig?.filename ? "ddsp_mod/" + fileUploadSetting.ddspSvcModelConfig?.filename : "" : "",
                    ddspSvcDiffusion: props.clientType == "DDSP-SVC" ? fileUploadSetting.ddspSvcDiffusion?.filename ? "ddsp_diff/" + fileUploadSetting.ddspSvcDiffusion?.filename : "" : "",
                    ddspSvcDiffusionConfig: props.clientType == "DDSP-SVC" ? fileUploadSetting.ddspSvcDiffusionConfig?.filename ? "ddsp_diff/" + fileUploadSetting.ddspSvcDiffusionConfig.filename : "" : "",
                }
            })

            if (fileUploadSetting.isHalf == undefined) {
                fileUploadSetting.isHalf = false
            }

            console.log("PARAMS:", params)

            const loadPromise = props.voiceChangerClient.loadModel(
                slot,
                fileUploadSetting.isHalf,
                params,
            )


            // サーバでロード中にキャッシュにセーブ
            storeToCache(slot, fileUploadSetting)
            await loadPromise

            fileUploadSetting.uploaded = true
            fileUploadSettings[slot] = fileUploadSetting
            setFileUploadSettings([...fileUploadSettings])


            setUploadProgress(0)
            setIsUploading(false)
            reloadServerInfo()
        }
    }, [fileUploadSettings, props.voiceChangerClient, props.clientType])


    const storeToCache = (slot: number, fileUploadSetting: FileUploadSetting) => {
        try {
            const saveData: FileUploadSetting = {
                isHalf: fileUploadSetting.isHalf, // キャッシュとしては不使用。guiで上書きされる。
                uploaded: false, // キャッシュから読み込まれるときには、まだuploadされていないから。
                defaultTune: fileUploadSetting.defaultTune,
                defaultIndexRatio: fileUploadSetting.defaultIndexRatio,
                defaultProtect: fileUploadSetting.defaultProtect,
                framework: fileUploadSetting.framework,
                params: fileUploadSetting.params,

                mmvcv13Config: fileUploadSetting.mmvcv13Config ? { data: fileUploadSetting.mmvcv13Config.data, filename: fileUploadSetting.mmvcv13Config.filename } : null,
                mmvcv13Model: fileUploadSetting.mmvcv13Model ? { data: fileUploadSetting.mmvcv13Model.data, filename: fileUploadSetting.mmvcv13Model.filename } : null,
                mmvcv15Config: fileUploadSetting.mmvcv15Config ? { data: fileUploadSetting.mmvcv15Config.data, filename: fileUploadSetting.mmvcv15Config.filename } : null,
                mmvcv15Model: fileUploadSetting.mmvcv15Model ? { data: fileUploadSetting.mmvcv15Model.data, filename: fileUploadSetting.mmvcv15Model.filename } : null,
                soVitsSvc40Config: fileUploadSetting.soVitsSvc40Config ? { data: fileUploadSetting.soVitsSvc40Config.data, filename: fileUploadSetting.soVitsSvc40Config.filename } : null,
                soVitsSvc40Model: fileUploadSetting.soVitsSvc40Model ? { data: fileUploadSetting.soVitsSvc40Model.data, filename: fileUploadSetting.soVitsSvc40Model.filename } : null,
                soVitsSvc40Cluster: fileUploadSetting.soVitsSvc40Cluster ? { data: fileUploadSetting.soVitsSvc40Cluster.data, filename: fileUploadSetting.soVitsSvc40Cluster.filename } : null,
                soVitsSvc40v2Config: fileUploadSetting.soVitsSvc40v2Config ? { data: fileUploadSetting.soVitsSvc40v2Config.data, filename: fileUploadSetting.soVitsSvc40v2Config.filename } : null,
                soVitsSvc40v2Model: fileUploadSetting.soVitsSvc40v2Model ? { data: fileUploadSetting.soVitsSvc40v2Model.data, filename: fileUploadSetting.soVitsSvc40v2Model.filename } : null,
                soVitsSvc40v2Cluster: fileUploadSetting.soVitsSvc40v2Cluster ? { data: fileUploadSetting.soVitsSvc40v2Cluster.data, filename: fileUploadSetting.soVitsSvc40v2Cluster.filename } : null,
                rvcModel: fileUploadSetting.rvcModel ? { data: fileUploadSetting.rvcModel.data, filename: fileUploadSetting.rvcModel.filename } : null,
                rvcIndex: fileUploadSetting.rvcIndex ? { data: fileUploadSetting.rvcIndex.data, filename: fileUploadSetting.rvcIndex.filename } : null,
                rvcFeature: fileUploadSetting.rvcFeature ? { data: fileUploadSetting.rvcFeature.data, filename: fileUploadSetting.rvcFeature.filename } : null,

                ddspSvcModel: fileUploadSetting.ddspSvcModel ? { data: fileUploadSetting.ddspSvcModel.data, filename: fileUploadSetting.ddspSvcModel.filename } : null,
                ddspSvcModelConfig: fileUploadSetting.ddspSvcModelConfig ? { data: fileUploadSetting.ddspSvcModelConfig.data, filename: fileUploadSetting.ddspSvcModelConfig.filename } : null,
                ddspSvcDiffusion: fileUploadSetting.ddspSvcDiffusion ? { data: fileUploadSetting.ddspSvcDiffusion.data, filename: fileUploadSetting.ddspSvcDiffusion.filename } : null,
                ddspSvcDiffusionConfig: fileUploadSetting.ddspSvcDiffusionConfig ? { data: fileUploadSetting.ddspSvcDiffusionConfig.data, filename: fileUploadSetting.ddspSvcDiffusionConfig.filename } : null,

                isSampleMode: fileUploadSetting.isSampleMode,
                sampleId: fileUploadSetting.sampleId,
                rvcIndexDownload: fileUploadSetting.rvcIndexDownload,
            }
            setItem(`${INDEXEDDB_KEY_MODEL_DATA}_${slot}`, saveData)
        } catch (e) {
            console.log("Excpetion:::::::::", e)
        }
    }



    const uploadAssets = useMemo(() => {
        return async (slot: number, name: ModelAssetName, file: File) => {
            if (!props.voiceChangerClient) return

            await _uploadFile2(file, (progress: number, _end: boolean) => {
                console.log(progress, _end)
            })
            const assetUploadSetting: AssetUploadSetting = {
                slot,
                name,
                file: file.name
            }
            await props.voiceChangerClient.uploadAssets(JSON.stringify(assetUploadSetting))
            reloadServerInfo()
        }
    }, [fileUploadSettings, props.voiceChangerClient, props.clientType])



    const reloadServerInfo = useMemo(() => {
        return async () => {

            if (!props.voiceChangerClient) return
            const res = await props.voiceChangerClient.getServerSettings()
            setServerSetting(res)
            const storeData = { ...res }
            storeData.recordIO = 0
            setItem(INDEXEDDB_KEY_SERVER, storeData)
        }
    }, [props.voiceChangerClient])

    const clearSetting = async () => {
        await removeItem(INDEXEDDB_KEY_SERVER)
        await removeItem(INDEXEDDB_KEY_MODEL_DATA)
        for (let i = 0; i < MAX_MODEL_SLOT_NUM; i++) {
            const modleKey = `${INDEXEDDB_KEY_MODEL_DATA}_${i}`
            await removeItem(modleKey)
        }
    }


    const getOnnx = async () => {
        return props.voiceChangerClient!.getOnnx()
    }

    const mergeModel = async (request: MergeModelRequest) => {
        const serverInfo = await props.voiceChangerClient!.mergeModel(request)
        setServerSetting(serverInfo)
        return serverInfo
    }

    const updateModelDefault = async () => {
        const serverInfo = await props.voiceChangerClient!.updateModelDefault()
        setServerSetting(serverInfo)
        return serverInfo
    }
    const updateModelInfo = async (slot: number, key: string, val: string) => {
        const serverInfo = await props.voiceChangerClient!.updateModelInfo(slot, key, val)
        setServerSetting(serverInfo)
        return serverInfo
    }

    return {
        serverSetting,
        updateServerSettings,
        clearSetting,
        reloadServerInfo,

        fileUploadSettings,
        setFileUploadSetting,
        loadModel,
        uploadModel,
        uploadProgress,
        isUploading,
        getOnnx,
        mergeModel,
        updateModelDefault,
        updateModelInfo,
        uploadAssets
    }
}