package com.datarecovery.master.module.imgrecover;

import androidx.lifecycle.LiveData;
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.runtime.ContextUtil;
import com.datarecovery.master.R;
import com.datarecovery.master.data.repositories.DeviceFuncRepository;
import com.datarecovery.master.module.member.MemberType;
import com.datarecovery.master.utils.FileUtil;
import com.datarecovery.master.utils.ImageDeepDetector;
import com.datarecovery.master.utils.MediaStoreHelper;
import com.datarecovery.master.utils.ToastUtil;

import org.reactivestreams.Subscription;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

import javax.inject.Inject;

import atmob.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import atmob.reactivex.rxjava3.annotations.NonNull;
import atmob.reactivex.rxjava3.core.FlowableSubscriber;
import atmob.reactivex.rxjava3.disposables.Disposable;
import atmob.rxjava.utils.RxJavaUtil;
import dagger.hilt.android.lifecycle.HiltViewModel;


@HiltViewModel
public class ImageRecoverViewModel extends BaseViewModel {


    private final long SCANNING_COUNTDOWN = 1000 * 60 * 6;

    private final MutableLiveData<List<ImageDeepDetector.ImageFile>> detectedPhotoImg = new MutableLiveData<>(new ArrayList<>());
    private final MutableLiveData<List<ImageDeepDetector.ImageFile>> detectedWxImg = new MutableLiveData<>(new ArrayList<>());
    private final MutableLiveData<List<ImageDeepDetector.ImageFile>> detectedQQImg = new MutableLiveData<>(new ArrayList<>());
    private final MutableLiveData<List<ImageDeepDetector.ImageFile>> detectedOtherImg = new MutableLiveData<>(new ArrayList<>());
    private final DeviceFuncRepository deviceFuncRepository;
    private LiveData<String> detectedPhotoTitle;
    private LiveData<String> detectedWxTitle;
    private LiveData<String> detectedQQTitle;
    private LiveData<String> detectedOtherTitle;

    private final SingleLiveEvent<ImageDeepDetector.ImageFile> previewEvent = new SingleLiveEvent<>();
    private final SingleLiveEvent<?> detectedFinish = new SingleLiveEvent<>();
    private final SingleLiveEvent<?> showClearDialog = new SingleLiveEvent<>();
    private final SingleLiveEvent<Boolean> showScanDialogEvent = new SingleLiveEvent<>();
    private final SingleLiveEvent<Boolean> showLoadingEvent = new SingleLiveEvent<>();
    private final SingleLiveEvent<?> notifyList = new SingleLiveEvent<>();
    private final MutableLiveData<String> barTitle = new MutableLiveData<>();
    private final MutableLiveData<Boolean> checkAll = new MutableLiveData<>(false);
    //总探测到的图片数量
    private int totalCount = 0;
    private final MutableLiveData<Integer> totalDetectedCount = new MutableLiveData<>();
    private final MutableLiveData<List<ImageDeepDetector.ImageFile>> selectedList = new MutableLiveData<>(new ArrayList<>());
    private LiveData<String> selectedCountTxt;
    private Disposable scanDisposable;
    private int type;


    @Inject
    public ImageRecoverViewModel(DeviceFuncRepository deviceFuncRepository) {
        this.deviceFuncRepository = deviceFuncRepository;
        barTitle.setValue(ContextUtil.getContext().getString(R.string.iamge_recover_all));
        initLiveData();
    }

    public LiveData<?> getShowClearDialog() {
        return showClearDialog;
    }

    public LiveData<?> getNotifyList() {
        return notifyList;
    }

    public LiveData<Boolean> getShowLoadingEvent() {
        return showLoadingEvent;
    }

    public LiveData<ImageDeepDetector.ImageFile> getPreviewEvent() {
        return previewEvent;
    }

    public LiveData<?> getDetectedFinish() {
        return detectedFinish;
    }

    public LiveData<Integer> getTotalDetectedCount() {
        return totalDetectedCount;
    }

    public LiveData<String> getSelectedCountTxt() {
        return selectedCountTxt;
    }

    public LiveData<List<ImageDeepDetector.ImageFile>> getSelectedList() {
        return selectedList;
    }

    public LiveData<List<ImageDeepDetector.ImageFile>> getDetectedPhotoImg() {
        return detectedPhotoImg;
    }

    public LiveData<List<ImageDeepDetector.ImageFile>> getDetectedWxImg() {
        return detectedWxImg;
    }

    public LiveData<List<ImageDeepDetector.ImageFile>> getDetectedQQImg() {
        return detectedQQImg;
    }

    public LiveData<List<ImageDeepDetector.ImageFile>> getDetectedOtherImg() {
        return detectedOtherImg;
    }

    public LiveData<String> getDetectedPhotoTitle() {
        return detectedPhotoTitle;
    }

    public LiveData<String> getDetectedWxTitle() {
        return detectedWxTitle;
    }

    public LiveData<String> getDetectedQQTitle() {
        return detectedQQTitle;
    }

    public LiveData<String> getDetectedOtherTitle() {
        return detectedOtherTitle;
    }

    public LiveData<Boolean> getShowScanDialogEvent() {
        return showScanDialogEvent;
    }


    public LiveData<Boolean> getCheckAll() {
        return checkAll;
    }

    public LiveData<String> getBarTitle() {
        return barTitle;
    }

    public int getType() {
        return type;
    }

    private void initLiveData() {
        detectedPhotoTitle = Transformations.map(detectedPhotoImg, list ->
                ContextUtil.getContext().getString(R.string.photo_count, (list == null || list.isEmpty()) ? 0 : list.size()));
        detectedWxTitle = Transformations.map(detectedWxImg, list ->
                ContextUtil.getContext().getString(R.string.wx_count, (list == null || list.isEmpty()) ? 0 : list.size()));
        detectedQQTitle = Transformations.map(detectedQQImg, list ->
                ContextUtil.getContext().getString(R.string.qq_count, (list == null || list.isEmpty()) ? 0 : list.size()));
        detectedOtherTitle = Transformations.map(detectedOtherImg, list ->
                ContextUtil.getContext().getString(R.string.other_count, (list == null || list.isEmpty()) ? 0 : list.size()));
    }

    public void onCheckAllClick(boolean isCheck) {
        checkAll.setValue(isCheck);
        List<ImageDeepDetector.ImageFile> selectList = getList(selectedList);
        setListCheck(detectedPhotoImg.getValue(), isCheck);
        setListCheck(detectedWxImg.getValue(), isCheck);
        setListCheck(detectedQQImg.getValue(), isCheck);
        setListCheck(detectedOtherImg.getValue(), isCheck);
        if (isCheck) {
            selectList.clear();
            selectList.addAll(getList(detectedPhotoImg));
            selectList.addAll(getList(detectedWxImg));
            selectList.addAll(getList(detectedQQImg));
            selectList.addAll(getList(detectedOtherImg));
        } else {
            selectList.clear();
        }
        selectedList.setValue(selectList);
    }

    private void setListCheck(List<ImageDeepDetector.ImageFile> list, boolean isCheck) {
        if (list == null || list.isEmpty()) {
            return;
        }
        for (ImageDeepDetector.ImageFile imageFile : list) {
            imageFile.setCheck(isCheck);
        }
    }


    private List<ImageDeepDetector.ImageFile> getList(LiveData<List<ImageDeepDetector.ImageFile>> liveData) {
        List<ImageDeepDetector.ImageFile> selectList = liveData.getValue();
        if (selectList == null) {
            selectList = new ArrayList<>();
        }
        return selectList;
    }

    public void startImageScanning() {
        if (scanDisposable != null && !scanDisposable.isDisposed()) {
            return;
        }
        ImageDeepDetector.detect(ContextUtil.getContext())
                .take(SCANNING_COUNTDOWN, TimeUnit.MILLISECONDS)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new FlowableSubscriber<List<ImageDeepDetector.ImageFile>>() {
                    @Override
                    public void onSubscribe(@NonNull Subscription s) {
                        s.request(Integer.MAX_VALUE);
                        scanDisposable = Disposable.fromSubscription(s);
                        addDisposable(scanDisposable);
                        showScanDialogEvent.setValue(true);
                        checkAll.setValue(false);
                        totalCount = 0;
                        totalDetectedCount.setValue(0);
                    }

                    @Override
                    public void onNext(List<ImageDeepDetector.ImageFile> imageFiles) {
                        if (imageFiles == null) {
                            return;
                        }
                        totalCount += imageFiles.size();
                        totalDetectedCount.setValue(totalCount);
                        for (ImageDeepDetector.ImageFile imageFile : imageFiles) {
                            MutableLiveData<List<ImageDeepDetector.ImageFile>> liveData;
                            if (imageFile.getCategory() == ImageDeepDetector.ImageFile.CATEGORY_GALLERY) {
                                liveData = detectedPhotoImg;
                            } else if (imageFile.getCategory() == ImageDeepDetector.ImageFile.CATEGORY_WECHAT) {
                                liveData = detectedWxImg;
                            } else if (imageFile.getCategory() == ImageDeepDetector.ImageFile.CATEGORY_QQ) {
                                liveData = detectedQQImg;
                            } else {
                                liveData = detectedOtherImg;
                            }
                            List<ImageDeepDetector.ImageFile> list = getList(liveData);
                            list.add(0, imageFile);
                            liveData.setValue(list);
                        }
                    }

                    @Override
                    public void onError(Throwable t) {
                        showScanDialogEvent.setValue(false);
                    }

                    @Override
                    public void onComplete() {
                        detectedFinish.call();
                    }
                });
    }

    public void cancelScan() {
        if (scanDisposable != null) scanDisposable.dispose();
    }

    public void setItemCheck(@NonNull ImageDeepDetector.ImageFile imageFile) {
        imageFile.setCheck(!imageFile.isCheck());
        List<ImageDeepDetector.ImageFile> list = getList(this.selectedList);
        if (imageFile.isCheck()) {
            list.add(imageFile);
        } else {
            list.remove(imageFile);
        }
        selectedList.setValue(list);
    }

    public void checkPreview(@NonNull ImageDeepDetector.ImageFile imageFile) {
        if (type == ImageRecoverActivity.Type.DELETE) {
            return;
        }
        if (type == ImageRecoverActivity.Type.RECOVER && !deviceFuncRepository.isHaveAuth(MemberType.APP_IMAGE_RECOVER)) {
            return;
        } else if (type == ImageRecoverActivity.Type.DELETE && !deviceFuncRepository.isHaveAuth(MemberType.APP_IMAGE_CLEAN)) {
            return;
        }
        previewEvent.setValue(imageFile);
    }

    public void onOperationClick() {
        if (type == ImageRecoverActivity.Type.DELETE) {
            showClearDialog.call();
        } else {
            onExportClick();
        }
    }

    public void executeImageDelete() {
        List<ImageDeepDetector.ImageFile> list = getList(selectedList);
        if (list.size() == 0) {
            return;
        }
        showLoadingEvent.setValue(true);
        RxJavaUtil.doInBackground(() -> {
            for (ImageDeepDetector.ImageFile item : list) {
                item.delete();
                MutableLiveData<List<ImageDeepDetector.ImageFile>> liveData;
                if (item.getCategory() == ImageDeepDetector.ImageFile.CATEGORY_GALLERY) {
                    liveData = detectedPhotoImg;
                } else if (item.getCategory() == ImageDeepDetector.ImageFile.CATEGORY_WECHAT) {
                    liveData = detectedWxImg;
                } else if (item.getCategory() == ImageDeepDetector.ImageFile.CATEGORY_QQ) {
                    liveData = detectedQQImg;
                } else {
                    liveData = detectedOtherImg;
                }
                List<ImageDeepDetector.ImageFile> itemList = getList(liveData);
                itemList.remove(item);
            }
            return true;
        }, o -> {
            checkAll.setValue(false);
            showLoadingEvent.setValue(false);
            ToastUtil.show(R.string.delete_success, ToastUtil.LENGTH_SHORT);
            list.clear();
            selectedList.setValue(list);
            notifyList.call();
        }, throwable -> {
            showLoadingEvent.setValue(false);
            ToastUtil.show(R.string.delete_fail, ToastUtil.LENGTH_SHORT);
        });
    }

    public void onExportClick() {
        List<ImageDeepDetector.ImageFile> list = getList(selectedList);
        if (list.size() == 0) {
            return;
        }
        if (type == ImageRecoverActivity.Type.RECOVER && !deviceFuncRepository.isHaveAuth(MemberType.APP_IMAGE_RECOVER)) {
            return;
        } else if (type == ImageRecoverActivity.Type.DELETE && !deviceFuncRepository.isHaveAuth(MemberType.APP_IMAGE_CLEAN)) {
            return;
        }
        showLoadingEvent.setValue(true);
        RxJavaUtil.doInBackground(() -> {
            for (ImageDeepDetector.ImageFile item : list) {
                MediaStoreHelper.saveToSharedStorage(MediaStoreHelper.TYPE_IMAGE, item.newInputStream(), FileUtil.getExportImageFileName(item.getName()));
                item.setCheck(false);
            }
            return true;
        }, o -> {
            checkAll.setValue(false);
            showLoadingEvent.setValue(false);
            ToastUtil.show(R.string.export_success, ToastUtil.LENGTH_SHORT);
            list.clear();
            selectedList.setValue(list);
        }, throwable -> {
            showLoadingEvent.setValue(false);
            ToastUtil.show(R.string.export_fail, ToastUtil.LENGTH_SHORT);
        });
    }


    public List<ImageDeepDetector.ImageFile> getAllDetectedList() {
        ArrayList<ImageDeepDetector.ImageFile> allList = new ArrayList<>();
        allList.addAll(getList(detectedPhotoImg));
        allList.addAll(getList(detectedWxImg));
        allList.addAll(getList(detectedQQImg));
        allList.addAll(getList(detectedOtherImg));
        return allList;
    }

    public int getPosition(@NonNull List<ImageDeepDetector.ImageFile> list, ImageDeepDetector.ImageFile target) {
        return list.indexOf(target);
    }


    public void setOperationType(@ImageRecoverActivity.Type int type) {
        this.type = type;
        switch (type) {
            case ImageRecoverActivity.Type.DELETE:
                selectedCountTxt = Transformations.map(selectedList, list -> {
                    if (list == null || list.isEmpty()) {
                        return ContextUtil.getContext().getString(R.string.delete);
                    }
                    return ContextUtil.getContext().getString(R.string.delete_count, list.size());
                });
                break;
            case ImageRecoverActivity.Type.RECOVER:
                selectedCountTxt = Transformations.map(selectedList, list -> {
                    if (list == null || list.isEmpty()) {
                        return ContextUtil.getContext().getString(R.string.export);
                    }
                    return ContextUtil.getContext().getString(R.string.export_count, list.size());
                });
                break;
        }
    }
}
