#pragma once

#ifndef IDUBBING_SDK_H
#define IDUBBING_SDK_H

#include "dubbing_global.h"
#include "idubbing_callback.h"
#include "dubbing_base.h"

#include <iostream>
#include <mutex>
#include <map>

namespace DUBBING {
    class DUBBING_CLIENT_EXPORT EngineConfig
    {
    public:
        EngineConfig();

        ~EngineConfig();

    public:
        // Retrieve the byte size of the sample format
        static int getSampleByteSize(AudioSampleFormat format);

    public:
        EngineConfig& resourcePath(const std::string& value);
        EngineConfig& token(const std::string& value);
        EngineConfig& sampleRate(int sampleRate);
        EngineConfig& enableLog(bool enable);
        EngineConfig& enableTransformLog(bool enable);
        EngineConfig& channel(int channel);
        EngineConfig& format(AudioSampleFormat sampleFormat);
        EngineConfig& muteOnFail(bool mute);
        EngineConfig& isSync(bool sync);
        EngineConfig& dubbbingCallBack(IDubbbingCallBack* callback);

    public:
        std::string getResourcePath();
        std::string getToken();
        int getSampleRate();
        bool getEnableLog();
        bool getEnableTransformLog();
        int getChannel();
        AudioSampleFormat getFormat();
        bool getMuteOnFail();
        bool getIsSync();
        IDubbbingCallBack* getDubbbingCallBack();


    private:
        std::string m_resourcePath;
        std::string m_token;
        int m_sampleRate = 48000;
        bool m_enableLog = false;
        bool m_enableTransformLog = false;
        int m_channel = 1;
        AudioSampleFormat m_format = AUDIO_PCM_S16;
        IDubbbingCallBack* m_dubbbingCallBack = nullptr;
        bool m_muteOnFail = true;
        bool m_isSync = false;
    };

    class DUBBING_CLIENT_EXPORT IDubbingEngine
    {
    public:
        IDubbingEngine();
        virtual ~IDubbingEngine();

        virtual void prepare() = 0;
        virtual void checkResources() = 0;
        virtual void setVoice(int voiceId) = 0;
        virtual int getCurrentVoice() = 0;
        virtual bool transform(char* data, int dataSize) = 0;
        virtual const char* getVoiceList() = 0;
        virtual void setMode(DubbingMode mode, float intonation, float pitch) = 0;
        virtual DubbingMode getMode() = 0;
        virtual float getIntonation() = 0;
        virtual float getPitch() = 0;
        virtual void proCalibration() = 0;
        virtual const char* getCalibrationFile() = 0;
        virtual void getSupportIntonation(float& min, float& max) = 0;
        virtual void getSupportPitch(float& min, float& max) = 0;
        virtual int getDelayMillis() = 0;
        virtual void start() = 0;
        virtual void stop() = 0;
        virtual void engineRelease() = 0;
        virtual DubbingEngineStatus getEngineStatus() = 0;

    private:
        static IDubbingEngine* s_instance;
        static std::mutex s_instanceMutex;
    };

    class DubbingEngineMgr
    {
    public:
        DubbingEngineMgr();
        virtual ~DubbingEngineMgr();
        static DubbingEngineMgr& instance();
        int64_t createDubbingEngineByPool(const DUBBING::EngineConfig& config);
        void destroyDubbingEngineByPool(int64_t IDubbingEngine);
        IDubbingEngine* getDubbingEngine(int64_t dubbingEngineId);

    private:
        std::map<int64_t, IDubbingEngine*> m_dubbingEngineMap;
    };
}

extern "C" DUBBING_CLIENT_EXPORT DUBBING::IDubbingEngine* __stdcall createDubbingEngine(const DUBBING::EngineConfig& config);
extern "C" DUBBING_CLIENT_EXPORT void __stdcall destroyDubbingEngine(DUBBING::IDubbingEngine* IDubbingEngine);

typedef void (*onDownloadCallback)(long long dubbingEngineId, int percent, int index, int count);
typedef void (*onCompleteCallback)(long long dubbingEngineId);
typedef void (*onErrorCallback)(long long dubbingEngineId);
typedef void (*onActionResultCallback)(long long dubbingEngineId, int actionType, int retCode, const char* msg);

extern "C" DUBBING_CLIENT_EXPORT int64_t __stdcall createDubbingEngineByPool(const char* resourcesPath = nullptr, int samplerate = 48000, int channel = 1, int format = AUDIO_PCM_S16, 
    bool enableLog = false, bool enableTransformLog = false, const char* token = nullptr,
    onDownloadCallback downloadCallback = nullptr, onCompleteCallback completeCallback = nullptr, onErrorCallback errorCallback = nullptr, onActionResultCallback actionResultCallback = nullptr);
extern "C" DUBBING_CLIENT_EXPORT void destroyDubbingEngineByPool(int64_t dubbingEngineId);
extern "C" DUBBING_CLIENT_EXPORT int __stdcall checkResources(int64_t dubbingEngineId);
extern "C" DUBBING_CLIENT_EXPORT int __stdcall prepare(int64_t dubbingEngineId);
extern "C" DUBBING_CLIENT_EXPORT int __stdcall setVoice(int64_t dubbingEngineId, int voiceId);
extern "C" DUBBING_CLIENT_EXPORT bool __stdcall transform(int64_t dubbingEngineId, char* data, int dataSize);
extern "C" DUBBING_CLIENT_EXPORT const char* __stdcall getVoiceList(int64_t dubbingEngineId);
extern "C" DUBBING_CLIENT_EXPORT int __stdcall getCurrentVoice();
extern "C" DUBBING_CLIENT_EXPORT void __stdcall setMode(int64_t dubbingEngineId, int mode, float p1, float p2);
extern "C" DUBBING_CLIENT_EXPORT int __stdcall getMode(int64_t dubbingEngineId);
extern "C" DUBBING_CLIENT_EXPORT float __stdcall getIntonation(int64_t dubbingEngineId);
extern "C" DUBBING_CLIENT_EXPORT float __stdcall getPitch(int64_t dubbingEngineId);
extern "C" DUBBING_CLIENT_EXPORT bool __stdcall proCalibration(int64_t dubbingEngineId);
extern "C" DUBBING_CLIENT_EXPORT const char* __stdcall getCalibrationFile(int64_t dubbingEngineId);
extern "C" DUBBING_CLIENT_EXPORT void __stdcall getSupportIntonation(int64_t dubbingEngineId, float* min, float* max);
extern "C" DUBBING_CLIENT_EXPORT void __stdcall getSupportPitch(int64_t dubbingEngineId, float* min, float* max);
extern "C" DUBBING_CLIENT_EXPORT int __stdcall getDelayMillis(int64_t dubbingEngineId);
extern "C" DUBBING_CLIENT_EXPORT void __stdcall start(int64_t dubbingEngineId);
extern "C" DUBBING_CLIENT_EXPORT void __stdcall stop(int64_t dubbingEngineId);
extern "C" DUBBING_CLIENT_EXPORT void __stdcall engineRelease(int64_t dubbingEngineId);
extern "C" DUBBING_CLIENT_EXPORT int __stdcall getEngineStatus(int64_t dubbingEngineId);


#endif