package com.eveningoutpost.dexdrip.Models;

import android.provider.BaseColumns;

import com.activeandroid.Model;
import com.activeandroid.annotation.Column;
import com.activeandroid.annotation.Table;
import com.activeandroid.query.Delete;
import com.activeandroid.query.Select;
import com.activeandroid.util.SQLiteUtils;
import com.eveningoutpost.dexdrip.UtilityModels.BgGraphBuilder;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.annotations.Expose;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by jamorham on 01/11/2016.
 */

// TODO change classname to match phone
@Table(name = "PebbleMovement", id = BaseColumns._ID)
public class PebbleMovement extends Model {

    private static boolean patched = false;
    private final static String TAG = "PebbleMovement";
    private final static boolean d = true; //false;

    @Expose
    @Column(name = "timestamp", unique = true, onUniqueConflicts = Column.ConflictAction.IGNORE)
    public long timestamp;

    @Expose
    @Column(name = "metric")
    public int metric;


    // patches and saves
    public Long saveit() {
        fixUpTable();
        return save();
    }

    public String toS() {
        final Gson gson = new GsonBuilder()
                .excludeFieldsWithoutExposeAnnotation()
                .create();
        return gson.toJson(this);
    }


    // static methods

    public static PebbleMovement createEfficientRecord(long timestamp_ms, int data)
    {
        PebbleMovement pm = last();
        if ((pm == null) || (data < pm.metric) || ((timestamp_ms - pm.timestamp) > (1000 * 30 * 5))) {
            pm = new PebbleMovement();
            pm.timestamp = timestamp_ms;
            if (d) UserError.Log.d(TAG,"Creating new record for timestamp: "+JoH.dateTimeText(timestamp_ms));
        } else {
            if (d) UserError.Log.d(TAG,"Merging pebble movement record: "+JoH.dateTimeText(timestamp_ms)+" vs old "+JoH.dateTimeText(pm.timestamp));
        }

        pm.metric = (int) (long) data;
        if(d) UserError.Log.d(TAG, "Saving Movement: " + pm.toS());
        pm.saveit();
        return pm;
    }

    public static PebbleMovement last() {
        try {
            return new Select()
                    .from(PebbleMovement.class)
                    .orderBy("timestamp desc")
                    .executeSingle();
        } catch (android.database.sqlite.SQLiteException e) {
            fixUpTable();
            return null;
        }
    }

    public static List<PebbleMovement> latestForGraph(int number, double startTime) {
        return latestForGraph(number, (long) startTime, Long.MAX_VALUE);
    }

    public static List<PebbleMovement> latestForGraph(int number, long startTime) {
        return latestForGraph(number, startTime, Long.MAX_VALUE);
    }

    public static List<PebbleMovement> latestForGraph(int number, long startTime, long endTime) {
        try {
            return new Select()
                    .from(PebbleMovement.class)
                    .where("timestamp >= " + Math.max(startTime, 0))
                    .where("timestamp <= " + endTime)
                    .orderBy("timestamp asc") // warn asc!
                    .limit(number)
                    .execute();
        } catch (android.database.sqlite.SQLiteException e) {
            fixUpTable();
            return new ArrayList<>();
        }
    }

    // expects pre-sorted in asc order?
    public static List<PebbleMovement> deltaListFromMovementList(List<PebbleMovement> mList) {
        int last_metric = -1;
        int temp_metric = -1;
        for (PebbleMovement pm : mList) {
            // first item in list
            if (last_metric == -1) {
                last_metric = pm.metric;
                pm.metric = 0;
            } else {
                // normal incrementing calculate delta
                if (pm.metric >= last_metric) {
                    temp_metric = pm.metric - last_metric;
                    last_metric = pm.metric;
                    pm.metric = temp_metric;
                } else {
                    last_metric = pm.metric;
                }
            }
        }
        return mList;
    }

    public static List<PebbleMovement> cleanup(int retention_days) {
        return new Delete()
                .from(PebbleMovement.class)
                .where("timestamp < ?", JoH.tsl() - (retention_days * 86400000L))
                .execute();
    }


    // create the table ourselves without worrying about model versioning and downgrading
    private static void fixUpTable() {
        if (patched) return;
        String[] patchup = {
                "CREATE TABLE PebbleMovement (_id INTEGER PRIMARY KEY AUTOINCREMENT);",
                "ALTER TABLE PebbleMovement ADD COLUMN timestamp INTEGER;",
                "ALTER TABLE PebbleMovement ADD COLUMN metric INTEGER;",
                "CREATE UNIQUE INDEX index_PebbleMovement_timestamp on PebbleMovement(timestamp);"};

        for (String patch : patchup) {
            try {
                SQLiteUtils.execSql(patch);
                //  UserError.Log.e(TAG, "Processed patch should not have succeeded!!: " + patch);
            } catch (Exception e) {
                //  UserError.Log.d(TAG, "Patch: " + patch + " generated exception as it should: " + e.toString());
            }
        }
        patched = true;
    }
}