package net.heartshield.data;

import android.content.Context;

import junit.framework.TestCase;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

import android.os.Environment;
import android.support.test.InstrumentationRegistry;
import android.util.Log;
import android.widget.Toast;

import net.heartshield.signal.DVec;
import net.heartshield.signal.IVec;

/**
 * @author David Madl (git@abanbytes.eu)
 * @date 2017-04-14
 */
public class MeasurementDataManagerTest extends TestCase {
    private static final String TAG = "MeasurementDataMgrTest";

    public void testFileCwd() {
        File f = new File("");
        System.out.println(f.getAbsolutePath());
        // /mnt/hsh/protos/dha3
        // :)
    }

    //private static final String TEST_STORAGE_DIR = "tmp";

    // TODO: setup routine clearing out and fileUtil.makeDirectories(FileUtil.PERSISTENT_DATA_DIR);

    public void testFileWrite() throws IOException {
        FileUtil fileUtil = new FileUtil(Environment.getExternalStorageDirectory());
        fileUtil.makeDirectories(FileUtil.PERSISTENT_DATA_DIR);
        fileUtil.writeDataFileContents("test.txt", "Hello world");
    }

    public void testClassifier() throws IOException {
        final CountDownLatch signal = new CountDownLatch(1);
    }

    public static Measurement measurement1() throws IOException {
        final Context appContext = InstrumentationRegistry.getContext();
        //InputStream is = appContext.getResources().openRawResource(net.heartshield.prevent.test.R.raw.measurement_1492009549_7f07f378);
        InputStream is = null;
        ////FileInputStream fis = new FileInputStream("app/src/androidTest/res/raw/measurement_1492009549_7F07F378.json");
        String js = FileUtil.readFileString(is);
        Measurement m = Measurement.deserialize(js);
        return m;
    }

    public static MeasurementResult measurement1result() throws IOException {
        final Context appContext = InstrumentationRegistry.getContext();
        //InputStream is = appContext.getResources().openRawResource(net.heartshield.prevent.test.R.raw.result_1492009549_7f07f378);
        InputStream is = null;
        ////FileInputStream fis = new FileInputStream("app/src/test/res/raw/result_1492009549_7F07F378.json");
        String js = FileUtil.readFileString(is);
        MeasurementResult r = MeasurementResult.deserialize(js);
        return r;
    }

    private void doTestClassifier(final CountDownLatch signal, final TestResults results) throws IOException {
        File externalStorage = new File(Environment.getExternalStorageDirectory(), "hsh-test");
        FileUtil fileUtil = new FileUtil(externalStorage); // avoid removing the production deployment's files
        fileUtil.makeDirectories(FileUtil.PERSISTENT_DATA_DIR);
        fileUtil.removeDataFile(FileUtil.MEASUREMENT_CACHE); // otherwise we keep overwriting the 1st measurement.

        final Measurement measurement = measurement1();
        final Context appContext = InstrumentationRegistry.getTargetContext();
        IMeasurementDataManager manager = MeasurementDataManager.getInstance(appContext);

        Log.i(TAG, "manager.create(measurement=" + measurement.getId().toString() + ")");
        manager.create(measurement, new IMeasurementDataManager.MeasurementResultListener() {
            @Override
            public void onResult(Measurement measurement) {
                Log.i(TAG, "onResult(measurement=" + measurement.getId().toString() + ")");
                results.measurement = measurement;
                signal.countDown();
            }

            @Override
            public void onError(Measurement measurement, IMeasurementDataManager.ErrorCode code, String message) {
                Toast.makeText(appContext, "create() failed", Toast.LENGTH_LONG).show();
                results.error = new RuntimeException("ErrorCode " + code.toString() + ": " + message);
                signal.countDown();
            }
        });
    }

    private class TestResults {
        Measurement measurement = null;
        Exception error = null;
    }

    public void testRemoteClassifier() throws IOException {
        //Log.i(TAG, "running testRemoteClassifier()...");
        final CountDownLatch signal = new CountDownLatch(1);

        final TestResults results = new TestResults();

        doTestClassifier(signal, results);

        try {
            // timeout must be longer than connection timeouts, see MeasurementDataManager.REQUEST_INITIAL_TIMEOUT_MS
            signal.await(30, TimeUnit.SECONDS); // wait for callback
        } catch (InterruptedException e) {
            e.printStackTrace();
            throw new AssertionError(e);
        }

        if(results.error != null)
            throw new AssertionError(results.error);

        if(results.measurement == null)
            throw new AssertionError("no results.error and no results.measurement - doTestClassifier() timed out without MeasurementResultListener callback!");

        //final double expected_pred = 0.105558563134; // ...
        final MeasurementResult expectedResult = measurement1result();

        assertNotNull(results.measurement.result);

        if(DVec.max(expectedResult.ibis) < 300)
            throw new IllegalStateException("expect ibis to be in ms");

        // round off to whole ms, to ignore server rounding differences (local testing vs. remote testing)
        results.measurement.result.ibis = DVec.round(results.measurement.result.ibis);
        expectedResult.ibis = DVec.round(expectedResult.ibis);

        String res = results.measurement.result.serialize();
        String expRes = expectedResult.serialize();

        assertEquals(expRes, res);
    }
}
