package com.atmob.voiceai.module.clonevoice;

import android.Manifest;
import android.net.Uri;
import android.os.CountDownTimer;

import androidx.lifecycle.LiveData;
import androidx.lifecycle.MediatorLiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.Transformations;

import com.atmob.app.lib.base.BaseViewModel;
import com.atmob.app.lib.livedata.SingleLiveEvent;
import com.atmob.common.data.KVUtils;
import com.atmob.common.runtime.ActivityUtil;
import com.atmob.common.runtime.ContextUtil;
import com.atmob.voiceai.R;
import com.atmob.voiceai.data.api.bean.CloneVoiceListBean;
import com.atmob.voiceai.data.consts.EventId;
import com.atmob.voiceai.data.repositories.CloneRepository;
import com.atmob.voiceai.data.repositories.MemberRepository;
import com.atmob.voiceai.data.repositories.VoiceAIRepository;
import com.atmob.voiceai.handlers.EventHandler;
import com.atmob.voiceai.helper.ErrorHelper;
import com.atmob.voiceai.module.cloning.VoiceCloningActivity;
import com.atmob.voiceai.module.main.MainActivity;
import com.atmob.voiceai.module.setting.SettingActivity;
import com.atmob.voiceai.module.subscription.SubscriptionPageActivity;
import com.atmob.voiceai.module.voiceai.VoiceAIFragment;
import com.atmob.voiceai.utils.BoxingUtil;
import com.atmob.voiceai.utils.DateUtil;
import com.atmob.voiceai.utils.FileUtils;
import com.atmob.voiceai.utils.PermissionUtil;
import com.atmob.voiceai.utils.SpannableUtil;
import com.atmob.voiceai.utils.ToastUtil;

import java.io.File;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import javax.inject.Inject;

import atmob.reactivex.rxjava3.annotations.NonNull;
import atmob.reactivex.rxjava3.core.SingleObserver;
import atmob.reactivex.rxjava3.disposables.Disposable;
import dagger.hilt.android.lifecycle.HiltViewModel;


@HiltViewModel
public class CloneVoiceViewModel extends BaseViewModel {


    public static final int RECORD_AUDIO_MAX_DURATION = 35 * 1000;
    public final int RECORD_AUDIO_MIN_DURATION = 20 * 1000;
    public static final String PERMISSION_AUDIO = Manifest.permission.RECORD_AUDIO;
    public final String RECORD_DIALOG_SHOW = "record_dialog_show";

    public static final int FILE_UPLOAD = 1;
    public static final int RECORD_UPLOAD = 2;

    private final MediatorLiveData<String> recordStateDesc = new MediatorLiveData<>();

    private final LiveData<String> recordTimeTxt;
    private final MutableLiveData<Integer> recordProgress = new MutableLiveData<>();
    private final MutableLiveData<Integer> recordProgressColor = new MutableLiveData<>();
    private final MutableLiveData<Boolean> showStopRecord = new MutableLiveData<>();
    private final MutableLiveData<String> uploadPreviewName = new MutableLiveData<>();
    private final MutableLiveData<String> uploadPreviewSize = new MutableLiveData<>();
    private final SingleLiveEvent<Integer> deleteEvent = new SingleLiveEvent<>();
    private final SingleLiveEvent<?> refreshAudioCurrentProgress = new SingleLiveEvent<>();
    private final SingleLiveEvent<?> requestAudioPermission = new SingleLiveEvent<>();
    private final SingleLiveEvent<?> startRecordAudioEvent = new SingleLiveEvent<>();
    private final SingleLiveEvent<?> stopRecordAudioEvent = new SingleLiveEvent<>();
    private final SingleLiveEvent<?> showRecordDialogEvent = new SingleLiveEvent<>();
    private final MutableLiveData<Boolean> isPlay = new MutableLiveData<>();
    private final MutableLiveData<Long> totalDuration = new MutableLiveData<>();
    private final MutableLiveData<Long> currentDuration = new MutableLiveData<>();
    private final MutableLiveData<CharSequence> cloneTip = new MutableLiveData<>();

    private final MediatorLiveData<Integer> cloneState = new MediatorLiveData<>();

    private final SingleLiveEvent<?> clickLocalUpload = new SingleLiveEvent<>();

    private final MutableLiveData<Uri> uploadVoiceUri = new MutableLiveData<>();
    private final MemberRepository memberRepository;
    private final CloneRepository cloneRepository;
    private final VoiceAIRepository voiceAIRepository;

    private boolean isSeekbarChanging;
    private Timer timer;

    File recordFile;
    private CountDownTimer countDownTimer;

    private int lastColor;

    private int color_0_20 = ContextUtil.getContext().getResources().getColor(R.color.voice_record_0_20);
    private int color_20_30 = ContextUtil.getContext().getResources().getColor(R.color.voice_record_20_30);
    private int color_exceed_30 = ContextUtil.getContext().getResources().getColor(R.color.voice_record_exceed_30);
    private String record_can_not = ContextUtil.getContext().getString(R.string.record_can_not);
    private String record_maybe_best = ContextUtil.getContext().getString(R.string.record_maybe_best);
    private String record_best = ContextUtil.getContext().getString(R.string.record_best);

    @Inject
    public CloneVoiceViewModel(MemberRepository memberRepository, CloneRepository cloneRepository, VoiceAIRepository voiceAIRepository) {
        this.memberRepository = memberRepository;
        this.cloneRepository = cloneRepository;
        this.voiceAIRepository = voiceAIRepository;
        initCloneTipTxt();
        initCloneState();
        recordStateDesc.addSource(recordProgress, progress -> {
            if (progress == null) {
                return;
            }
            int newColor;
            String newText;
            if (progress >= 0 && progress <= 20000) {
                newColor = color_0_20;
                newText = record_can_not;
            } else if (progress > 20000 && progress <= 30000) {
                newColor = color_20_30;
                newText = record_maybe_best;
            } else {
                newColor = color_exceed_30;
                newText = record_best;
            }
            if (newColor != lastColor) {
                lastColor = newColor;
                recordStateDesc.setValue(newText);
                recordProgressColor.setValue(newColor);
            }
        });
        recordTimeTxt = Transformations.map(recordProgress, progress -> {
            if (progress == null) {
                return "00:00.00";
            }
            return DateUtil.formatNormalDate("mm:ss.SS", progress);
        });
    }


    public LiveData<String> getRecordTimeTxt() {
        return recordTimeTxt;
    }

    public LiveData<String> getRecordStateDesc() {
        return recordStateDesc;
    }

    public LiveData<Integer> getRecordProgress() {
        return recordProgress;
    }

    public LiveData<Integer> getRecordProgressColor() {
        return recordProgressColor;
    }

    public long getRecordMaxTime() {
        return RECORD_AUDIO_MAX_DURATION;
    }

    public LiveData<Boolean> getShowStopRecord() {
        return showStopRecord;
    }

    public LiveData<?> getStopRecordAudioEvent() {
        return stopRecordAudioEvent;
    }

    public LiveData<?> getStartRecordAudioEvent() {
        return startRecordAudioEvent;
    }

    public LiveData<?> getRequestAudioPermission() {
        return requestAudioPermission;
    }

    public LiveData<?> getShowRecordDialogEvent() {
        return showRecordDialogEvent;
    }

    public LiveData<Integer> getDeleteEvent() {
        return deleteEvent;
    }

    public LiveData<String> getUploadPreviewName() {
        return uploadPreviewName;
    }

    public LiveData<String> getUploadPreviewSize() {
        return uploadPreviewSize;
    }

    public LiveData<?> getRefreshAudioCurrentProgress() {
        return refreshAudioCurrentProgress;
    }


    public LiveData<Boolean> getIsPlay() {
        return isPlay;
    }


    public LiveData<Long> getCurrentDuration() {
        return currentDuration;
    }

    public LiveData<Long> getTotalDuration() {
        return totalDuration;
    }

    public LiveData<Uri> getUploadVoiceUri() {
        return uploadVoiceUri;
    }

    public LiveData<?> getClickLocalUpload() {
        return clickLocalUpload;
    }

    public LiveData<Integer> getCloneState() {
        return cloneState;
    }

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


    public LiveData<CharSequence> getCloneTip() {
        return cloneTip;
    }

    public LiveData<Boolean> getIsMember() {
        return memberRepository.getIsMember();
    }


    public void setSeekbarChanging(boolean seekbarChanging) {
        isSeekbarChanging = seekbarChanging;
    }


    public void startMediaTimer() {
        if (timer != null) {
            return;
        }
        timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                if (isSeekbarChanging) {
                    return;
                }
                refreshAudioCurrentProgress.postValue(null);
            }
        }, 0, 25);
    }


    public void setCurrentDuration(long duration) {
        if (duration >= 0) {
            currentDuration.setValue(duration);
        }
    }

    public void setVoicePlay(boolean isPlay) {
        this.isPlay.setValue(isPlay);
    }

    public void setTotalDuration(long duration) {
        if (duration >= 0) {
            totalDuration.setValue(duration);
        }
    }

    private void initCloneState() {
        cloneState.addSource(cloneRepository.getCloneVoiceList(), list -> {
            uploadVoiceUri.setValue(null);
            if (list == null || list.isEmpty()) {
                cloneState.setValue(CloneState.NO_UPLOAD_DATA);
            } else {
                cloneState.setValue(CloneState.CLONE_SUCCESS);
            }
        });
    }

    private void initCloneTipTxt() {
        String allTxt = ContextUtil.getContext().getString(R.string.clone_voice_tip);
        String targetTxt = ContextUtil.getContext().getString(R.string.clone_voice_tip_create);
        cloneTip.setValue(SpannableUtil.getSpannableStringBuilder(allTxt, targetTxt, ContextUtil.getContext().getResources().getColor(R.color.colorPrimaryVariant), false));
    }


    public void requestCloneVoice(int type, File file) {
        cloneRepository.requestVoiceClone(type, file);
        VoiceCloningActivity.start(ActivityUtil.getTopActivity());
    }

    public void deleteClone(int id) {
        cloneRepository.cloneDelete(id).subscribe(new SingleObserver<Object>() {
            @Override
            public void onSubscribe(@NonNull Disposable d) {
                addDisposable(d);
            }

            @Override
            public void onSuccess(@NonNull Object o) {

            }

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

    public void onGoSubscriptionClick() {
        SubscriptionPageActivity.start(ActivityUtil.getTopActivity());
    }

    public void onSettingClick() {
        SettingActivity.start(ActivityUtil.getTopActivity());
    }

    public void onLocalUploadClick() {
        EventHandler.report(EventId.cloneupload_001);
        clickLocalUpload.call();
    }

    public void setLocalVoiceUri(@NonNull Uri uri) {
        //判断是否符合要求
        //文件小于3M  时长大于20s且小于30s
        long durationLong = FileUtils.getAudioDurationFromUri(ContextUtil.getContext(), uri);
        if (durationLong < 20000 || durationLong > 30000) {
            ToastUtil.show(R.string.clone_voice_duration_error, ToastUtil.LENGTH_SHORT);
            return;
        }
        long fileSize = FileUtils.getFileSizeFromUri(ContextUtil.getContext(), uri);
        if (fileSize > 3 * 1024 * 1024) {
            ToastUtil.show(R.string.clone_voice_size_error, ToastUtil.LENGTH_SHORT);
            return;
        }
        String name = FileUtils.getFileNameFromUri(ContextUtil.getContext(), uri);
        uploadPreviewName.setValue(name);
        uploadPreviewSize.setValue(FileUtils.formatShortBytes(fileSize));
        this.uploadVoiceUri.setValue(uri);
        cloneState.setValue(CloneState.UPLOAD_CHOICE_LOCAL);
    }

    public void onLocalReSelectClick() {
        returnOriginalState();
    }

    public void onReRecordClick() {
        returnOriginalState();
    }

    public void onCloneVoiceClick(int state) {
        Uri value = uploadVoiceUri.getValue();
        if (value == null) {
            return;
        }
        if (!BoxingUtil.boxing(memberRepository.getIsMember().getValue())) {
            SubscriptionPageActivity.start(ActivityUtil.getTopActivity());
            return;
        }
        File file = FileUtils.uriToFileApiQ(value, ContextUtil.getContext());
        if (state == CloneState.UPLOAD_CHOICE_RECORDING) {
            requestCloneVoice(RECORD_UPLOAD, file);
        } else {
            requestCloneVoice(FILE_UPLOAD, file);
        }
    }


    public void useCloneVoiceClick() {
        EventHandler.report(EventId.cloneuse_001);
        MainActivity.start(ActivityUtil.getTopActivity(), VoiceAIFragment.class);
        List<CloneVoiceListBean> list = cloneRepository.getCloneVoiceList().getValue();
        if (list == null || list.isEmpty()) {
            return;
        }
        voiceAIRepository.setUseClonedVoiceEvent(list.get(0).getId());
    }

    public void onDeleteClick() {
        EventHandler.report(EventId.clonedelete_001);
        List<CloneVoiceListBean> list = cloneRepository.getCloneVoiceList().getValue();
        if (list == null || list.isEmpty()) {
            ToastUtil.show(R.string.no_clone_data, ToastUtil.LENGTH_SHORT);
            return;
        }
        deleteEvent.setValue(list.get(0).getId());
    }

    public void onRecordClick() {
        EventHandler.report(EventId.clonerecord_001);
        if (!PermissionUtil.hasPermission(PERMISSION_AUDIO)) {
            requestAudioPermission.call();
            return;
        }
        onPermissionNext();
    }

    public void onPermissionNext() {
        if (KVUtils.getDefault().getBoolean(RECORD_DIALOG_SHOW, true)) {
            showRecordDialogEvent.call();
        } else {
            startRecordAudio();
        }
    }


    public void startRecordAudio() {
        startRecordAudioEvent.call();
        recordProgress.setValue(0);
        cloneState.setValue(CloneState.RECORDING_VOICE);
        showStopRecord.setValue(true);
        startCountDown();
    }

    private void startCountDown() {
        countDownTimer = new CountDownTimer(RECORD_AUDIO_MAX_DURATION, 25) {
            @Override
            public void onTick(long millisUntilFinished) {
                recordProgress.setValue((int) (RECORD_AUDIO_MAX_DURATION - millisUntilFinished));
            }

            @Override
            public void onFinish() {
                stopRecordAudio(true);
            }
        };
        countDownTimer.start();
    }

    public void onDialogKnowClick(boolean isCheck) {
        if (isCheck) {
            KVUtils.getDefault().putBoolean(RECORD_DIALOG_SHOW, false);
        }
        startRecordAudio();
    }

    @Override
    protected void onCleared() {
        super.onCleared();
        if (timer != null) {
            timer.cancel();
            timer = null;
        }
        if (countDownTimer != null) {
            countDownTimer.cancel();
        }
    }

    public String getRecordAudioFilePath() {
        File cacheFile = FileUtils.getVoiceCacheFile();
        recordFile = new File(cacheFile, "record_audio.mp3");
        return recordFile.getPath();
    }

    public void onRecordingClick(boolean isRecording, int stopProgress) {
        boolean isReset = stopProgress < RECORD_AUDIO_MIN_DURATION;
        if (isReset) {
            showStopRecord.setValue(false);
        }
        if (isRecording) {
            stopRecordAudio(!isReset);
        } else {
            returnOriginalState();
        }
    }

    private void stopRecordAudio(boolean isOk) {
        if (countDownTimer != null) {
            countDownTimer.cancel();
        }
        stopRecordAudioEvent.call();
        if (isOk) {
            Uri uri = Uri.fromFile(recordFile);
            long fileSize = recordFile.length();
            uploadVoiceUri.setValue(uri);
            uploadPreviewName.setValue(recordFile.getName());
            uploadPreviewSize.setValue(FileUtils.formatShortBytes(fileSize));
            cloneState.setValue(CloneState.UPLOAD_CHOICE_RECORDING);
        }
    }

    private void returnOriginalState() {
        this.uploadVoiceUri.setValue(null);
        this.isPlay.setValue(false);
        setCurrentDuration(0);
        cloneState.setValue(CloneState.NO_UPLOAD_DATA);
        if (countDownTimer != null) {
            countDownTimer.cancel();
        }
        if (timer != null) {
            timer.cancel();
            timer = null;
        }
    }
}
