package com.atmob.voiceai.data.repositories;


import android.net.Uri;
import android.text.TextUtils;

import androidx.annotation.IntDef;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;

import com.atmob.app.lib.handler.RxHttpHandler;
import com.atmob.app.lib.livedata.SingleLiveEvent;
import com.atmob.common.runtime.ContextUtil;
import com.atmob.voiceai.data.api.AtmobApi;
import com.atmob.voiceai.data.api.GenerateApi;
import com.atmob.voiceai.data.api.bean.CloneVoiceListBean;
import com.atmob.voiceai.data.api.request.BaseRequest;
import com.atmob.voiceai.data.api.request.CloneDeleteRequest;
import com.atmob.voiceai.data.api.request.VoiceCloneRequest;
import com.atmob.voiceai.data.api.response.VoiceCloneListResponse;
import com.atmob.voiceai.data.api.response.VoiceCloneResponse;
import com.atmob.voiceai.helper.ErrorHelper;
import com.atmob.voiceai.utils.FileUtils;
import com.atmob.voiceai.utils.ReflectionUtil;
import com.atmob.voiceai.utils.ToastUtil;
import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;

import java.io.File;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import javax.inject.Inject;
import javax.inject.Singleton;

import atmob.okhttp3.MediaType;
import atmob.okhttp3.MultipartBody;
import atmob.okhttp3.RequestBody;
import atmob.reactivex.rxjava3.annotations.NonNull;
import atmob.reactivex.rxjava3.core.Single;
import atmob.reactivex.rxjava3.core.SingleObserver;
import atmob.reactivex.rxjava3.disposables.Disposable;
import atmob.rxjava.utils.RxJavaUtil;

@Singleton
public class CloneRepository {


    private final AtmobApi atmobApi;
    private final VoiceAIRepository voiceAIRepository;
    private final GenerateApi generateApi;

    private final MutableLiveData<List<CloneVoiceListBean>> cloneVoiceList = new MutableLiveData<>();
    private final MutableLiveData<Integer> cloneUploadState = new MutableLiveData<>();

    private boolean requestListFlag = false;
    private boolean requestCloneFlag = false;

    @IntDef({UploadState.CLONING, UploadState.UPLOAD_SUCCESS, UploadState.ERROR})
    public @interface UploadState {
        int CLONING = 1;
        int UPLOAD_SUCCESS = 2;
        int ERROR = 3;
    }

    @Inject
    public CloneRepository(AtmobApi atmobApi, GenerateApi generateApi, VoiceAIRepository voiceAIRepository) {
        this.atmobApi = atmobApi;
        this.generateApi = generateApi;
        this.voiceAIRepository = voiceAIRepository;
        refreshCloneList();
    }

    public LiveData<Integer> getCloneUploadState() {
        return cloneUploadState;
    }

    public LiveData<List<CloneVoiceListBean>> getCloneVoiceList() {
        return cloneVoiceList;
    }

    public void refreshCloneList() {
        if (requestListFlag) {
            return;
        }
        getCloneList().subscribe(new SingleObserver<VoiceCloneListResponse>() {
            @Override
            public void onSubscribe(@NonNull Disposable d) {
                requestListFlag = true;
            }

            @Override
            public void onSuccess(@NonNull VoiceCloneListResponse voiceCloneListResponse) {
                requestListFlag = false;
                cloneVoiceList.setValue(voiceCloneListResponse.getCloneVoiceList());
            }

            @Override
            public void onError(@NonNull Throwable e) {
                requestListFlag = false;
                ErrorHelper.errorThrowableToast(e, ToastUtil.LENGTH_SHORT);
            }
        });
    }

    public void requestVoiceClone(int type, @NonNull File file) {
        if (requestCloneFlag) {
            return;
        }
        voiceClone(type, file).subscribe(new SingleObserver<VoiceCloneResponse>() {
            @Override
            public void onSubscribe(@NonNull Disposable d) {
                requestCloneFlag = true;
                cloneUploadState.setValue(UploadState.CLONING);
            }

            @Override
            public void onSuccess(@NonNull VoiceCloneResponse voiceCloneResponse) {
                requestCloneFlag = false;
                cloneUploadState.setValue(UploadState.UPLOAD_SUCCESS);
            }

            @Override
            public void onError(@NonNull Throwable e) {
                requestCloneFlag = false;
                cloneUploadState.setValue(UploadState.ERROR);
                ErrorHelper.errorThrowableToast(e, ToastUtil.LENGTH_SHORT);
            }
        });
    }

    private Single<VoiceCloneListResponse> getCloneList() {
        return atmobApi.getCloneList(new BaseRequest())
                .compose(RxHttpHandler.handle(true))
                .retryWhen(RxJavaUtil.exponentialBackOff(null, 3, TimeUnit.SECONDS))
                .compose(RxJavaUtil.SingleSchedule.io2Main());
    }

    public Single<Object> cloneDelete(int id) {
        return atmobApi.cloneDelete(new CloneDeleteRequest(id))
                .compose(RxHttpHandler.handle(true))
                .compose(RxJavaUtil.SingleSchedule.io2Main())
                .doOnSuccess(response -> {
                    refreshCloneList();
                    voiceAIRepository.setCloneExecuteSuccessEvent();
                });

    }

    private Single<VoiceCloneResponse> voiceClone(int type, File file) {
        RequestBody fileRQ = RequestBody.create(file, MediaType.parse("audio/*"));
        MultipartBody.Builder builder = new MultipartBody.Builder();
        VoiceCloneRequest voiceCloneRequest = new VoiceCloneRequest(type);
        List<Field> allField = ReflectionUtil.getAllField(VoiceCloneRequest.class);
        for (Field field : allField) {
            try {
                field.setAccessible(true);
                Object value = field.get(voiceCloneRequest);
                SerializedName serializedName = field.getAnnotation(SerializedName.class);
                String name = null;
                if (serializedName != null && serializedName.value() != null) {
                    name = serializedName.value();
                } else {
                    name = field.getName();
                }
                if (value != null) {
                    builder.addFormDataPart(name, value.toString());
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        builder.addFormDataPart("file", file.getName(), fileRQ);
        builder.setType(MultipartBody.FORM);
        RequestBody body = builder.build();
        return generateApi.voiceClone(body)
                .compose(RxHttpHandler.handle(false))
                .compose(RxJavaUtil.SingleSchedule.io2Main())
                .doOnSuccess(response -> {
                    refreshCloneList();
                    voiceAIRepository.setCloneExecuteSuccessEvent();
                });
    }
}
