package cgmblelib.database.source.db;

import androidx.annotation.NonNull;
import androidx.lifecycle.LiveData;

import java.util.Date;
import java.util.List;

import cgmblelib.base.BApplication;
import cgmblelib.database.dao.DaoDevice;
import cgmblelib.database.entity.PocDevice;
import cgmblelib.database.source.SourceDevice;
import cgmblelib.qr.QRInformation;
import cgmblelib.utils.AppExecutors;
import cgmblelib.utils.SharedPreferencesLibraryUtil;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.functions.Consumer;
import io.reactivex.schedulers.Schedulers;
import ist.com.sdk.EDevice;

/**
 * Created by minyuchun on 2019/10/25.
 *
 * @author minyuchun
 */
public class DeviceDBDataSource extends DBDataSource implements SourceDevice {
    /**
     * 持久化 -- 单例
     */
    private static volatile DeviceDBDataSource INSTANCE;
    /**
     * dao
     */
    private DaoDevice mDaoDevice;
    /***
     * 线程池
     */
    private AppExecutors mAppExecutors;


    private DeviceDBDataSource(@NonNull AppExecutors appExecutors,
                               @NonNull DaoDevice daoDevice) {
        mAppExecutors = appExecutors;
        mDaoDevice = daoDevice;
    }


    public static DeviceDBDataSource getInstance(@NonNull AppExecutors appExecutors, @NonNull DaoDevice daoDevice) {
        if (INSTANCE == null) {
            synchronized (DeviceDBDataSource.class) {
                if (INSTANCE == null) {
                    INSTANCE = new DeviceDBDataSource(appExecutors, daoDevice);
                }
            }
        }
        return INSTANCE;
    }

    @Override
    public long insertDeviceIoThread(PocDevice device) {
        try {
            CheckIoThread();
            return mDaoDevice.insert(device);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }

    @Override
    public long insertDeviceIoThread(String address, String name) {
        try {
            CheckIoThread();
            PocDevice mPocBoundDevice = new PocDevice();
            mPocBoundDevice.setAddress(address);
            mPocBoundDevice.setName(name);
            Date date = new Date();
            mPocBoundDevice.setBindDate(date);
            mPocBoundDevice.setConnectDate(date);
            SharedPreferencesLibraryUtil sharedPreferencesLibraryUtil = new SharedPreferencesLibraryUtil(BApplication.getContext());
            QRInformation qrInformation = sharedPreferencesLibraryUtil.getQRInformation();
            int algorithm = EDevice.getEnumDevice(name).getAlgorithm();
            mPocBoundDevice.setAlgorithmVersion(algorithm);
            QRInformation information = sharedPreferencesLibraryUtil.getQRInformation();
            EDevice eDevice = EDevice.getEnumDevice(name);
            if (information != null && information.isEffective(name, information.getR(), information.getK())) {
                mPocBoundDevice.setQrMessage(information.getQRMessage());
            }
            mPocBoundDevice.setInitCount(eDevice.getInitNumber());
            mPocBoundDevice.setEndCount(eDevice.getEndNumber());
            return insertDeviceIoThread(mPocBoundDevice);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }

    @Override
    public void deleteDevice(PocDevice device) {
        Runnable deleteRunnable = () -> mDaoDevice.delete(device);
        mAppExecutors.diskIO().execute(deleteRunnable);
    }

    @Override
    public void deleteAllDevices() {
        throw new UnsupportedOperationException("TBD");
    }

    @Override
    public void deleteAllDeviceData() {
        Runnable deleteRunnable = () -> mDaoDevice.clearDeviceTable();
        mAppExecutors.diskIO().execute(deleteRunnable);
    }

    @Override
    public void updateDevice(PocDevice device) {
        Runnable updateRunnable = () -> mDaoDevice.update(device);
        mAppExecutors.diskIO().execute(updateRunnable);
    }

    @Override
    public int updateDeviceIoThread(PocDevice device) {
        try {
            CheckIoThread();
            return mDaoDevice.update(device);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }

    @Override
    public PocDevice getLatestDeviceIoThread() {
        try {
            CheckIoThread();
            return mDaoDevice.getLatestDevice();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    @Override
    public PocDevice getLatestDeviceIoThread(String address) {
        try {
            CheckIoThread();
            return mDaoDevice.getLatestDeviceByAddress(address);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public LiveData<PocDevice> getLiveDataLatestDeviceIoThread() {
        return mDaoDevice.getLiveDataLatestDevice();
    }

    @Override
    public PocDevice getDeviceByIdIoThread(int deviceId) {
        try {
            CheckIoThread();
            return mDaoDevice.getDeviceById(deviceId);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public List<PocDevice> getDeviceListGroupByAddressIoThread() {
        try {
            CheckIoThread();
            return mDaoDevice.getDifferentAddressDevices();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public List<PocDevice> getDeviceListByAddressIoThread(@NonNull String address) {
        try {
            CheckIoThread();
            return mDaoDevice.getDifferentDateDevicesByAddress(address);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public void getLatestFlowableDevice(Consumer<PocDevice> consumer) {
        mDaoDevice.getFlowableLatestDevice()
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(consumer);
    }
}
