package com.datarecovery.master.module.audiorecover;

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.imgrecover.ImageRecoverActivity;
import com.datarecovery.master.module.member.MemberType;
import com.datarecovery.master.utils.FileUtil;
import com.datarecovery.master.utils.FilesSearch;
import com.datarecovery.master.utils.MediaStoreHelper;
import com.datarecovery.master.utils.ToastUtil;

import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;

import java.util.ArrayList;
import java.util.Collections;
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.disposables.Disposable;
import atmob.rxjava.utils.RxJavaUtil;
import dagger.hilt.android.lifecycle.HiltViewModel;


@HiltViewModel
public class AudioRecoverViewModel extends BaseViewModel {

    private final long SCANNING_COUNTDOWN = 1000 * 60 * 6;
    private final LiveData<String> selectedCountTxt;
    private final MutableLiveData<Boolean> checkAll = new MutableLiveData<>(false);
    private final List<FilesSearch.DocumentFile> originalDetectedList = new ArrayList<>();
    private final MutableLiveData<List<FilesSearch.DocumentFile>> detectedVideoList = new MutableLiveData<>(new ArrayList<>());
    private final MutableLiveData<List<FilesSearch.DocumentFile>> selectedList = new MutableLiveData<>(new ArrayList<>());
    private final SingleLiveEvent<?> detectedFinish = new SingleLiveEvent<>();
    private final SingleLiveEvent<?> showFilterPopup = new SingleLiveEvent<>();
    private final SingleLiveEvent<Boolean> showScanDialogEvent = new SingleLiveEvent<>();
    private final SingleLiveEvent<?> notifyAudioData = new SingleLiveEvent<>();
    private final SingleLiveEvent<Boolean> showLoadingEvent = new SingleLiveEvent<>();
    private final DeviceFuncRepository deviceFuncRepository;
    private int totalCount = 0;
    private final MutableLiveData<Integer> totalDetectedCount = new MutableLiveData<>();
    private final MutableLiveData<Boolean> isDateFilterArrowUp = new MutableLiveData<>(false);
    private final MutableLiveData<Boolean> isSizeSortArrowUp = new MutableLiveData<>(false);
    private final MutableLiveData<Integer> dataFilterCondition = new MutableLiveData<>();

    private Disposable scanDisposable;

    private final int[] dateFilterArray = new int[]{
            R.string.all,
            R.string.within_a_week,
            R.string.away_a_week,
            R.string.a_month_ago,
            R.string.a_year_ago
    };

    public LiveData<?> getNotifyAudioData() {
        return notifyAudioData;
    }

    @Inject
    public AudioRecoverViewModel(DeviceFuncRepository deviceFuncRepository) {
        this.deviceFuncRepository = deviceFuncRepository;
        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());
        });
    }


    public LiveData<Integer> getDataFilterCondition() {
        return dataFilterCondition;
    }

    public LiveData<Boolean> getIsDateFilterArrowUp() {
        return isDateFilterArrowUp;
    }

    public LiveData<Boolean> getIsSizeSortArrowUp() {
        return isSizeSortArrowUp;
    }

    public LiveData<?> getShowFilterPopup() {
        return showFilterPopup;
    }

    public int[] getDateFilterArray() {
        return dateFilterArray;
    }

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

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

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

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

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

    public LiveData<List<FilesSearch.DocumentFile>> getDetectedVideoList() {
        return detectedVideoList;
    }

    public LiveData<List<FilesSearch.DocumentFile>> getSelectedList() {
        return selectedList;
    }

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

    public void startAudioScanning() {
        if (scanDisposable != null && !scanDisposable.isDisposed()) {
            return;
        }
        FilesSearch.search(ContextUtil.getContext(), FilesSearch.DocumentFile.AUDIO)
                .take(SCANNING_COUNTDOWN, TimeUnit.MILLISECONDS)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Subscriber<List<FilesSearch.DocumentFile>>() {
                    @Override
                    public void onSubscribe(Subscription s) {
                        s.request(Integer.MAX_VALUE);
                        scanDisposable = Disposable.fromSubscription(s);
                        addDisposable(scanDisposable);
                        showScanDialogEvent.setValue(true);
                        totalCount = 0;
                        totalDetectedCount.setValue(0);
                        getList(detectedVideoList).clear();
                        originalDetectedList.clear();
                    }

                    @Override
                    public void onNext(List<FilesSearch.DocumentFile> documentFiles) {
                        if (documentFiles == null) {
                            return;
                        }
                        totalCount += documentFiles.size();
                        totalDetectedCount.setValue(totalCount);
                        originalDetectedList.addAll(0, documentFiles);
                        List<FilesSearch.DocumentFile> list = getList(detectedVideoList);
                        list.addAll(0, documentFiles);
                        detectedVideoList.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();
    }

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

    public void onCheckAllClick(boolean isCheck) {
        checkAll.setValue(isCheck);
        List<FilesSearch.DocumentFile> detectedList = getList(detectedVideoList);
        for (FilesSearch.DocumentFile videoFile : detectedList) {
            videoFile.setCheck(isCheck);
        }
        List<FilesSearch.DocumentFile> selectedList = getList(this.selectedList);
        if (isCheck) {
            selectedList.clear();
            selectedList.addAll(detectedList);
        } else {
            selectedList.clear();
        }
        this.selectedList.setValue(selectedList);
    }

    public void onExportClick() {
        List<FilesSearch.DocumentFile> list = selectedList.getValue();
        if (list == null || list.size() == 0) {
            return;
        }
        if (!deviceFuncRepository.isHaveAuth(MemberType.APP_AUDIO_RECOVER)) {
            return;
        }
        showLoadingEvent.setValue(true);
        RxJavaUtil.doInBackground(() -> {
            for (FilesSearch.DocumentFile item : list) {
                MediaStoreHelper.saveToSharedStorage(MediaStoreHelper.TYPE_AUDIO, item.newInputStream(), FileUtil.getCreateFileName(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 void setItemCheck(@NonNull FilesSearch.DocumentFile file) {
        file.setCheck(!file.isCheck());
        List<FilesSearch.DocumentFile> list = getList(selectedList);
        if (file.isCheck()) {
            list.add(file);
        } else {
            list.remove(file);
        }
        selectedList.setValue(list);
    }

    public void onDateFilterClick() {
        showFilterPopup.call();
        isDateFilterArrowUp.setValue(true);
    }

    public void setIsDateFilterArrowDown() {
        isDateFilterArrowUp.setValue(false);
    }

    public void onSizeSortClick(boolean isUp) {
        List<FilesSearch.DocumentFile> list = getList(detectedVideoList);
        Collections.sort(list, (o1, o2) -> {
            if (o1.getSize() > o2.getSize()) {
                return (isUp) ? 1 : -1;
            } else if (o1.getSize() < o2.getSize()) {
                return (isUp) ? -1 : 1;
            }
            return 0;
        });
        isSizeSortArrowUp.setValue(isUp);
        notifyAudioData.call();
    }

    public void setFilter(int filterTxtId) {
        if (filterTxtId == R.string.all) {
            dataFilterCondition.setValue(null);
        } else {
            dataFilterCondition.setValue(filterTxtId);
        }
        if (filterTxtId == R.string.all) {
            getAllList();
        } else if (filterTxtId == R.string.within_a_week) {
            getWithinWeekList();
        } else if (filterTxtId == R.string.away_a_week) {
            getAwayWeekList();
        } else if (filterTxtId == R.string.a_month_ago) {
            getMonthAgoList();
        } else if (filterTxtId == R.string.a_year_ago) {
            getYearAgoList();
        }
        notifyAudioData.call();
    }

    private void getAllList() {
        if (originalDetectedList.isEmpty()) {
            return;
        }
        List<FilesSearch.DocumentFile> list = getList(detectedVideoList);
        list.clear();
        list.addAll(originalDetectedList);
    }

    private List<FilesSearch.DocumentFile> getAwayWeekList() {
        if (originalDetectedList.isEmpty()) {
            return originalDetectedList;
        }
        List<FilesSearch.DocumentFile> list = getList(detectedVideoList);
        list.clear();
        for (FilesSearch.DocumentFile file : originalDetectedList) {
            if (file.getLastModified() < System.currentTimeMillis() - 1000L * 60 * 60 * 24 * 7) {
                list.add(file);
            }
        }
        return list;
    }

    private List<FilesSearch.DocumentFile> getYearAgoList() {
        if (originalDetectedList.isEmpty()) {
            return originalDetectedList;
        }
        List<FilesSearch.DocumentFile> list = getList(detectedVideoList);
        list.clear();
        for (FilesSearch.DocumentFile file : originalDetectedList) {
            if (file.getLastModified() < System.currentTimeMillis() - 1000L * 60 * 60 * 24 * 365) {
                list.add(file);
            }
        }
        return list;
    }

    private List<FilesSearch.DocumentFile> getMonthAgoList() {
        if (originalDetectedList.isEmpty()) {
            return originalDetectedList;
        }
        List<FilesSearch.DocumentFile> list = getList(detectedVideoList);
        list.clear();
        for (FilesSearch.DocumentFile file : originalDetectedList) {
            if (file.getLastModified() < System.currentTimeMillis() - 1000L * 60 * 60 * 24 * 30) {
                list.add(file);
            }
        }
        return list;
    }


    private List<FilesSearch.DocumentFile> getWithinWeekList() {
        if (originalDetectedList.isEmpty()) {
            return originalDetectedList;
        }
        List<FilesSearch.DocumentFile> list = getList(detectedVideoList);
        list.clear();
        for (FilesSearch.DocumentFile file : originalDetectedList) {
            if (file.getLastModified() > System.currentTimeMillis() - 1000L * 60 * 60 * 24 * 7) {
                list.add(file);
            }
        }
        return list;
    }

}
