package info.nightscout.androidaps.activities;

import android.graphics.Color;
import android.graphics.Rect;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;

import androidx.recyclerview.widget.LinearLayoutManager;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;

import javax.inject.Inject;

import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.db.TDD;
import info.nightscout.androidaps.events.EventPumpStatusChanged;
import info.nightscout.androidaps.interfaces.ActivePluginProvider;
import info.nightscout.androidaps.interfaces.CommandQueueProvider;
import info.nightscout.androidaps.logging.StacktraceLoggerWrapper;
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunction;
import info.nightscout.androidaps.plugins.pump.danaR.DanaRPlugin;
import info.nightscout.androidaps.plugins.pump.danaR.events.EventDanaRSyncStatus;
import info.nightscout.androidaps.plugins.pump.danaRKorean.DanaRKoreanPlugin;
import info.nightscout.androidaps.plugins.pump.danaRS.DanaRSPlugin;
import info.nightscout.androidaps.plugins.pump.danaRv2.DanaRv2Plugin;
import info.nightscout.androidaps.plugins.pump.insight.LocalInsightPlugin;
import info.nightscout.androidaps.queue.Callback;
import info.nightscout.androidaps.utils.FabricPrivacy;
import info.nightscout.androidaps.utils.SafeParse;
import info.nightscout.androidaps.utils.resources.ResourceHelper;
import info.nightscout.androidaps.utils.sharedPreferences.SP;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;

public class TDDStatsActivity extends NoSplashAppCompatActivity {
    @Inject ResourceHelper resourceHelper;
    @Inject RxBusWrapper rxBus;
    @Inject SP sp;
    @Inject ProfileFunction profileFunction;
    @Inject ActivePluginProvider activePlugin;
    @Inject DanaRSPlugin danaRSPlugin;
    @Inject DanaRPlugin danaRPlugin;
    @Inject DanaRv2Plugin danaRv2Plugin;
    @Inject DanaRKoreanPlugin danaRKoreanPlugin;
    @Inject LocalInsightPlugin localInsightPlugin;
    @Inject ConfigBuilderPlugin configBuilderPlugin;
    @Inject CommandQueueProvider commandQueue;

    private static Logger log = StacktraceLoggerWrapper.getLogger(TDDStatsActivity.class);
    private CompositeDisposable disposable = new CompositeDisposable();

    TextView statusView, statsMessage, totalBaseBasal2;
    EditText totalBaseBasal;
    Button reloadButton;
    LinearLayoutManager llm;
    TableLayout tl, ctl, etl;
    String TBB;
    double magicNumber;
    DecimalFormat decimalFormat;

    List<TDD> historyList = new ArrayList<>();
    List<TDD> dummies;

    public TDDStatsActivity() {
        super();
    }

    @Override
    protected void onResume() {
        super.onResume();
        disposable.add(rxBus
                .toObservable(EventPumpStatusChanged.class)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(event -> statusView.setText(event.getStatus(resourceHelper)), exception -> FabricPrivacy.getInstance().logException(exception))
        );
        disposable.add(rxBus
                .toObservable(EventDanaRSyncStatus.class)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(event -> {
                    log.debug("EventDanaRSyncStatus: " + event.getMessage());
                    statusView.setText(event.getMessage());
                }, exception -> FabricPrivacy.getInstance().logException(exception))
        );
    }

    @Override
    protected void onPause() {
        super.onPause();
        disposable.clear();
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            View myView = getCurrentFocus();
            if (myView instanceof EditText) {
                Rect rect = new Rect();
                myView.getGlobalVisibleRect(rect);
                if (!rect.contains((int) event.getRawX(), (int) event.getRawY())) {
                    myView.clearFocus();
                }
            }
        }
        return super.dispatchTouchEvent(event);
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.danar_statsactivity);
        getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
        statusView = findViewById(R.id.danar_stats_connection_status);
        reloadButton = findViewById(R.id.danar_statsreload);
        totalBaseBasal = findViewById(R.id.danar_stats_editTotalBaseBasal);
        totalBaseBasal2 = findViewById(R.id.danar_stats_editTotalBaseBasal2);
        statsMessage = findViewById(R.id.danar_stats_Message);

        statusView.setVisibility(View.GONE);
        statsMessage.setVisibility(View.GONE);

        totalBaseBasal2.setEnabled(false);
        totalBaseBasal2.setClickable(false);
        totalBaseBasal2.setFocusable(false);
        totalBaseBasal2.setInputType(0);

        decimalFormat = new DecimalFormat("0.000");
        llm = new LinearLayoutManager(this);

        TBB = sp.getString("TBB", "10.00");

        Profile profile = profileFunction.getProfile();
        if (profile != null) {
            double cppTBB = profile.baseBasalSum();
            TBB = decimalFormat.format(cppTBB);
            sp.putString("TBB", TBB);
        }
        totalBaseBasal.setText(TBB);

        if (!activePlugin.getActivePump().getPumpDescription().needsManualTDDLoad)
            reloadButton.setVisibility(View.GONE);

        // stats table
        tl = findViewById(R.id.main_table);
        TableRow tr_head = new TableRow(this);
        tr_head.setBackgroundColor(Color.DKGRAY);
        tr_head.setLayoutParams(new TableLayout.LayoutParams(
                TableLayout.LayoutParams.MATCH_PARENT,
                TableLayout.LayoutParams.WRAP_CONTENT));

        TextView label_date = new TextView(this);
        label_date.setText(resourceHelper.gs(R.string.danar_stats_date));
        label_date.setTextColor(Color.WHITE);
        tr_head.addView(label_date);

        TextView label_basalrate = new TextView(this);
        label_basalrate.setText(resourceHelper.gs(R.string.danar_stats_basalrate));
        label_basalrate.setTextColor(Color.WHITE);
        tr_head.addView(label_basalrate);

        TextView label_bolus = new TextView(this);
        label_bolus.setText(resourceHelper.gs(R.string.danar_stats_bolus));
        label_bolus.setTextColor(Color.WHITE);
        tr_head.addView(label_bolus);

        TextView label_tdd = new TextView(this);
        label_tdd.setText(resourceHelper.gs(R.string.danar_stats_tdd));
        label_tdd.setTextColor(Color.WHITE);
        tr_head.addView(label_tdd);

        TextView label_ratio = new TextView(this);
        label_ratio.setText(resourceHelper.gs(R.string.danar_stats_ratio));
        label_ratio.setTextColor(Color.WHITE);
        tr_head.addView(label_ratio);

        // add stats headers to tables
        tl.addView(tr_head, new TableLayout.LayoutParams(
                TableLayout.LayoutParams.MATCH_PARENT,
                TableLayout.LayoutParams.WRAP_CONTENT));

        // cumulative table
        ctl = findViewById(R.id.cumulative_table);
        TableRow ctr_head = new TableRow(this);
        ctr_head.setBackgroundColor(Color.DKGRAY);
        ctr_head.setLayoutParams(new TableLayout.LayoutParams(
                TableLayout.LayoutParams.MATCH_PARENT,
                TableLayout.LayoutParams.WRAP_CONTENT));

        TextView label_cum_amount_days = new TextView(this);
        label_cum_amount_days.setText(resourceHelper.gs(R.string.danar_stats_amount_days));
        label_cum_amount_days.setTextColor(Color.WHITE);
        ctr_head.addView(label_cum_amount_days);

        TextView label_cum_tdd = new TextView(this);
        label_cum_tdd.setText(resourceHelper.gs(R.string.danar_stats_tdd));
        label_cum_tdd.setTextColor(Color.WHITE);
        ctr_head.addView(label_cum_tdd);

        TextView label_cum_ratio = new TextView(this);
        label_cum_ratio.setText(resourceHelper.gs(R.string.danar_stats_ratio));
        label_cum_ratio.setTextColor(Color.WHITE);
        ctr_head.addView(label_cum_ratio);

        // add cummulative headers to tables
        ctl.addView(ctr_head, new TableLayout.LayoutParams(
                TableLayout.LayoutParams.MATCH_PARENT,
                TableLayout.LayoutParams.WRAP_CONTENT));

        // expontial table
        etl = findViewById(R.id.expweight_table);
        TableRow etr_head = new TableRow(this);
        etr_head.setBackgroundColor(Color.DKGRAY);
        etr_head.setLayoutParams(new TableLayout.LayoutParams(
                TableLayout.LayoutParams.MATCH_PARENT,
                TableLayout.LayoutParams.WRAP_CONTENT));

        TextView label_exp_weight = new TextView(this);
        label_exp_weight.setText(resourceHelper.gs(R.string.danar_stats_weight));
        label_exp_weight.setTextColor(Color.WHITE);
        etr_head.addView(label_exp_weight);

        TextView label_exp_tdd = new TextView(this);
        label_exp_tdd.setText(resourceHelper.gs(R.string.danar_stats_tdd));
        label_exp_tdd.setTextColor(Color.WHITE);
        etr_head.addView(label_exp_tdd);

        TextView label_exp_ratio = new TextView(this);
        label_exp_ratio.setText(resourceHelper.gs(R.string.danar_stats_ratio));
        label_exp_ratio.setTextColor(Color.WHITE);
        etr_head.addView(label_exp_ratio);

        // add expontial headers to tables
        etl.addView(etr_head, new TableLayout.LayoutParams(
                TableLayout.LayoutParams.MATCH_PARENT,
                TableLayout.LayoutParams.WRAP_CONTENT));

        reloadButton.setOnClickListener(v -> {
            runOnUiThread(() -> {
                reloadButton.setVisibility(View.GONE);
                statusView.setVisibility(View.VISIBLE);
                statsMessage.setVisibility(View.VISIBLE);
                statsMessage.setText(resourceHelper.gs(R.string.danar_stats_warning_Message));
            });
            commandQueue.loadTDDs(new Callback() {
                @Override
                public void run() {
                    loadDataFromDB();
                    runOnUiThread(() -> {
                        reloadButton.setVisibility(View.VISIBLE);
                        statusView.setVisibility(View.GONE);
                        statsMessage.setVisibility(View.GONE);
                    });
                }
            });
        });

        totalBaseBasal.setOnEditorActionListener((v, actionId, event) -> {
            if (actionId == EditorInfo.IME_ACTION_DONE) {
                totalBaseBasal.clearFocus();
                return true;
            }
            return false;
        });

        totalBaseBasal.setOnFocusChangeListener((v, hasFocus) -> {
            if (hasFocus) {
                totalBaseBasal.getText().clear();
            } else {
                sp.putString("TBB", totalBaseBasal.getText().toString());
                TBB = sp.getString("TBB", "");
                loadDataFromDB();
                InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
                imm.hideSoftInputFromWindow(totalBaseBasal.getWindowToken(), 0);
            }
        });

        loadDataFromDB();
    }

    private void loadDataFromDB() {
        historyList = MainApp.getDbHelper().getTDDs();

        //only use newest 10
        historyList = historyList.subList(0, Math.min(10, historyList.size()));

        //fill single gaps
        dummies = new LinkedList();
        DateFormat df = new SimpleDateFormat("dd.MM.", Locale.getDefault());
        for (int i = 0; i < historyList.size() - 1; i++) {
            TDD elem1 = historyList.get(i);
            TDD elem2 = historyList.get(i + 1);

            if (!df.format(new Date(elem1.date)).equals(df.format(new Date(elem2.date + 25 * 60 * 60 * 1000)))) {
                TDD dummy = new TDD();
                dummy.date = elem1.date - 24 * 60 * 60 * 1000;
                dummy.basal = elem1.basal / 2;
                dummy.bolus = elem1.bolus / 2;
                dummies.add(dummy);
                elem1.basal /= 2;
                elem1.bolus /= 2;
            }
        }
        historyList.addAll(dummies);
        Collections.sort(historyList, (lhs, rhs) -> (int) (rhs.date - lhs.date));

        runOnUiThread(() -> {
            cleanTable(tl);
            cleanTable(ctl);
            cleanTable(etl);
            DateFormat df1 = new SimpleDateFormat("dd.MM.", Locale.getDefault());

            if (TextUtils.isEmpty(TBB)) {
                totalBaseBasal.setError("Please Enter Total Base Basal");
                return;
            } else {
                magicNumber = SafeParse.stringToDouble(TBB);
            }

            magicNumber *= 2;
            totalBaseBasal2.setText(decimalFormat.format(magicNumber));

            int i = 0;
            double sum = 0d;
            double weighted03 = 0d;
            double weighted05 = 0d;
            double weighted07 = 0d;


            //TDD table
            for (TDD record : historyList) {
                double tdd = record.getTotal();

                // Create the table row
                TableRow tr = new TableRow(TDDStatsActivity.this);
                if (i % 2 != 0) tr.setBackgroundColor(Color.DKGRAY);
                if (dummies.contains(record)) {
                    tr.setBackgroundColor(Color.argb(125, 255, 0, 0));
                }
                tr.setId(100 + i);
                tr.setLayoutParams(new TableLayout.LayoutParams(
                        TableLayout.LayoutParams.MATCH_PARENT,
                        TableLayout.LayoutParams.WRAP_CONTENT));

                // Here create the TextView dynamically
                TextView labelDATE = new TextView(TDDStatsActivity.this);
                labelDATE.setId(200 + i);
                labelDATE.setText(df1.format(new Date(record.date)));
                labelDATE.setTextColor(Color.WHITE);
                tr.addView(labelDATE);

                TextView labelBASAL = new TextView(TDDStatsActivity.this);
                labelBASAL.setId(300 + i);
                labelBASAL.setText(resourceHelper.gs(R.string.formatinsulinunits, record.basal));
                labelBASAL.setTextColor(Color.WHITE);
                tr.addView(labelBASAL);

                TextView labelBOLUS = new TextView(TDDStatsActivity.this);
                labelBOLUS.setId(400 + i);
                labelBOLUS.setText(resourceHelper.gs(R.string.formatinsulinunits, record.bolus));
                labelBOLUS.setTextColor(Color.WHITE);
                tr.addView(labelBOLUS);

                TextView labelTDD = new TextView(TDDStatsActivity.this);
                labelTDD.setId(500 + i);
                labelTDD.setText(resourceHelper.gs(R.string.formatinsulinunits, tdd));
                labelTDD.setTextColor(Color.WHITE);
                tr.addView(labelTDD);

                TextView labelRATIO = new TextView(TDDStatsActivity.this);
                labelRATIO.setId(600 + i);
                labelRATIO.setText(Math.round(100 * tdd / magicNumber) + "%");
                labelRATIO.setTextColor(Color.WHITE);
                tr.addView(labelRATIO);

                // add stats rows to tables
                tl.addView(tr, new TableLayout.LayoutParams(
                        TableLayout.LayoutParams.MATCH_PARENT,
                        TableLayout.LayoutParams.WRAP_CONTENT));

                i++;
            }

            i = 0;

            //cumulative TDDs
            for (TDD record : historyList) {
                if (!historyList.isEmpty() && df1.format(new Date(record.date)).equals(df1.format(new Date()))) {
                    //Today should not be included
                    continue;
                }
                i++;

                sum = sum + record.getTotal();

                // Create the cumtable row
                TableRow ctr = new TableRow(TDDStatsActivity.this);
                if (i % 2 == 0) ctr.setBackgroundColor(Color.DKGRAY);
                ctr.setId(700 + i);
                ctr.setLayoutParams(new TableLayout.LayoutParams(
                        TableLayout.LayoutParams.MATCH_PARENT,
                        TableLayout.LayoutParams.WRAP_CONTENT));

                // Here create the TextView dynamically
                TextView labelDAYS = new TextView(TDDStatsActivity.this);
                labelDAYS.setId(800 + i);
                labelDAYS.setText("" + i);
                labelDAYS.setTextColor(Color.WHITE);
                ctr.addView(labelDAYS);

                TextView labelCUMTDD = new TextView(TDDStatsActivity.this);
                labelCUMTDD.setId(900 + i);
                labelCUMTDD.setText(resourceHelper.gs(R.string.formatinsulinunits, sum / i));
                labelCUMTDD.setTextColor(Color.WHITE);
                ctr.addView(labelCUMTDD);

                TextView labelCUMRATIO = new TextView(TDDStatsActivity.this);
                labelCUMRATIO.setId(1000 + i);
                labelCUMRATIO.setText(Math.round(100 * sum / i / magicNumber) + "%");
                labelCUMRATIO.setTextColor(Color.WHITE);
                ctr.addView(labelCUMRATIO);

                // add cummulative rows to tables
                ctl.addView(ctr, new TableLayout.LayoutParams(
                        TableLayout.LayoutParams.MATCH_PARENT,
                        TableLayout.LayoutParams.WRAP_CONTENT));
            }

            if (isOldData(historyList) && activePlugin.getActivePump().getPumpDescription().needsManualTDDLoad) {
                statsMessage.setVisibility(View.VISIBLE);
                statsMessage.setText(resourceHelper.gs(R.string.danar_stats_olddata_Message));

            } else {
                tl.setBackgroundColor(Color.TRANSPARENT);
            }

            if (!historyList.isEmpty() && df1.format(new Date(historyList.get(0).date)).equals(df1.format(new Date()))) {
                //Today should not be included
                historyList.remove(0);
            }

            Collections.reverse(historyList);

            i = 0;

            for (TDD record : historyList) {
                double tdd = record.getTotal();
                if (i == 0) {
                    weighted03 = tdd;
                    weighted05 = tdd;
                    weighted07 = tdd;

                } else {
                    weighted07 = (weighted07 * 0.3 + tdd * 0.7);
                    weighted05 = (weighted05 * 0.5 + tdd * 0.5);
                    weighted03 = (weighted03 * 0.7 + tdd * 0.3);
                }
                i++;
            }

            // Create the exptable row
            TableRow etr = new TableRow(TDDStatsActivity.this);
            if (i % 2 != 0) etr.setBackgroundColor(Color.DKGRAY);
            etr.setId(1100 + i);
            etr.setLayoutParams(new TableLayout.LayoutParams(
                    TableLayout.LayoutParams.MATCH_PARENT,
                    TableLayout.LayoutParams.WRAP_CONTENT));

            // Here create the TextView dynamically
            TextView labelWEIGHT = new TextView(TDDStatsActivity.this);
            labelWEIGHT.setId(1200 + i);
            labelWEIGHT.setText("0.3\n" + "0.5\n" + "0.7");
            labelWEIGHT.setTextColor(Color.WHITE);
            etr.addView(labelWEIGHT);

            TextView labelEXPTDD = new TextView(TDDStatsActivity.this);
            labelEXPTDD.setId(1300 + i);
            labelEXPTDD.setText(resourceHelper.gs(R.string.formatinsulinunits, weighted03) + "\n" +
                    resourceHelper.gs(R.string.formatinsulinunits, weighted05) + "\n" +
                    resourceHelper.gs(R.string.formatinsulinunits, weighted07));
            labelEXPTDD.setTextColor(Color.WHITE);
            etr.addView(labelEXPTDD);

            TextView labelEXPRATIO = new TextView(TDDStatsActivity.this);
            labelEXPRATIO.setId(1400 + i);
            labelEXPRATIO.setText(Math.round(100 * weighted03 / magicNumber) + "%\n"
                    + Math.round(100 * weighted05 / magicNumber) + "%\n"
                    + Math.round(100 * weighted07 / magicNumber) + "%");
            labelEXPRATIO.setTextColor(Color.WHITE);
            etr.addView(labelEXPRATIO);

            // add exponentail rows to tables
            etl.addView(etr, new TableLayout.LayoutParams(
                    TableLayout.LayoutParams.MATCH_PARENT,
                    TableLayout.LayoutParams.WRAP_CONTENT));
        });
    }

    private void cleanTable(TableLayout table) {
        int childCount = table.getChildCount();
        // Remove all rows except the first one
        if (childCount > 1) {
            table.removeViews(1, childCount - 1);
        }
    }

    public boolean isOldData(List<TDD> historyList) {

        boolean startsYesterday = danaRPlugin.isEnabled() || danaRSPlugin.isEnabled() || danaRv2Plugin.isEnabled() || danaRKoreanPlugin.isEnabled() || localInsightPlugin.isEnabled();

        DateFormat df = new SimpleDateFormat("dd.MM.", Locale.getDefault());
        return (historyList.size() < 3 || !(df.format(new Date(historyList.get(0).date)).equals(df.format(new Date(System.currentTimeMillis() - (startsYesterday ? 1000 * 60 * 60 * 24 : 0))))));
    }
}