package net.heartshield.prevent;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.text.format.DateFormat;
import android.view.KeyEvent;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.SeekBar;
import android.widget.TableLayout;
import android.widget.TextView;
import android.widget.Toast;

import net.heartshield.data.AppInfo;
import net.heartshield.data.DataManagerFactory;
import net.heartshield.data.DoctorDetails;
import net.heartshield.data.IMeasurementDataManager;
import net.heartshield.data.Measurement;
import net.heartshield.data.MeasurementId;
import net.heartshield.data.MeasurementResult;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.util.Date;

/**
 * @author David Madl (git@abanbytes.eu)
 * @date 2017-06-05
 */
public class EditActivity extends Activity {
    private static final String TAG = "EditActivity";
    private IMeasurementDataManager mDataManager;
    private Measurement mMeasurement;
    private AppInfo mAppInfo;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_edit);

        mDateFormat = DateFormat.getDateFormat(this);
        mTimeFormat = DateFormat.getTimeFormat(this);

        int[] defocusableEditTexts = new int[]{R.id.chol_total, R.id.other_diag, R.id.other_med};
        for(int id : defocusableEditTexts) {
            EditText editText = (EditText) findViewById(id);
            editText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
                @Override
                public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
                    if(actionId == EditorInfo.IME_ACTION_DONE) {

                        // hide soft keyboard
                        InputMethodManager inputManager =
                                (InputMethodManager) EditActivity.this.
                                        getSystemService(Context.INPUT_METHOD_SERVICE);
                        inputManager.hideSoftInputFromWindow(
                                EditActivity.this.getCurrentFocus().getWindowToken(),
                                InputMethodManager.HIDE_NOT_ALWAYS);

                        return true;
                    }
                    return false;
                }
            });
        }
    }

    private boolean mShowPersonalTrackingInfo;

    @Override
    protected void onResume() {
        super.onResume();

        mAppInfo = AppInfo.getInstance(this);
        mShowPersonalTrackingInfo = mAppInfo.devSettings.showPersonalTracking;

        mDataManager = DataManagerFactory.getInstance().getDataManager(getApplicationContext());
        mDataManager.startBackgroundThread();
        mDataManager.startBackgroundSync();

        MeasurementId id = (MeasurementId) getIntent().getSerializableExtra("measurementId");
        Measurement measurement;
        try {
            measurement = mDataManager.retrieve(id);
            mMeasurement = measurement;
        } catch (IOException e) {
            e.printStackTrace();
            Toast.makeText(EditActivity.this, "Local filesystem failure: " + e.getMessage(), Toast.LENGTH_LONG).show();

            // go back to Home screen
            Intent intent = new Intent(EditActivity.this, HomeActivity.class);
            startActivity(intent);
            mMeasurement = null;
            return;
        }

        showMeasurement(measurement);
    }

    @Override
    protected void onPause() {
        super.onPause();
        mDataManager.stopBackgroundThread();
    }

    @Override
    public void onBackPressed() {
        super.onBackPressed();
        save(null);
    }

    public void save(View view) {
        updateMeasurement(mMeasurement);

        mDataManager.update(mMeasurement, new IMeasurementDataManager.MeasurementResultListener() {
            @Override
            public void onResult(Measurement measurement) {
                Toast.makeText(EditActivity.this, "Measurement saved.", Toast.LENGTH_LONG).show();
            }

            @Override
            public void onError(Measurement measurement, IMeasurementDataManager.ErrorCode code, String message) {
                // it's still marked dirty, and will be transmitted next time
                Toast.makeText(EditActivity.this, "Failed to save edit.", Toast.LENGTH_LONG).show();
            }
        });

        finish();
    }

    public void discard(View view) {
        finish();
    }

    private static class Element {
        public String name;
        public int id;

        Element(String name, int id) {
            this.name = name;
            this.id = id;
        }
    }

    private static final Element[] CHECKBOXES = {
            new Element("smoker", R.id.smoker),
            new Element("diabetes", R.id.diabetes),
            new Element("hypertension", R.id.hypertension),
            new Element("cvd", R.id.cvd),
            new Element("no_cvd", R.id.no_cvd),
            new Element("no_afib", R.id.no_afib),
            new Element("afib_sin", R.id.afib_sin),
            new Element("afib_now", R.id.afib_now),
            new Element("no_cad", R.id.no_cad),
            new Element("cad_lt70", R.id.cad_lt70),
            new Element("cad_gt70", R.id.cad_gt70),
            new Element("betablocker", R.id.betablocker),
            new Element("antiarrhythmic", R.id.antiarrhythmic),
            new Element("antihypertensive", R.id.antihypertensive)
    };

    private static final Element[] TEXTBOXES = {
            new Element("bp_sys", R.id.bp_sys),
            new Element("bp_dia", R.id.bp_dia),
            new Element("chol_hdl", R.id.chol_hdl),
            new Element("chol_total", R.id.chol_total),
            new Element("other_med", R.id.other_med),
            new Element("other_diag", R.id.other_diag),
    };

    private java.text.DateFormat mDateFormat;
    private java.text.DateFormat mTimeFormat;

    private static int getInt(Integer i) {
        if(i == null)
            return 0;
        else
            return i;
    }

    /** Measurement -> UI */
    private void showMeasurement(Measurement measurement) {
        if(measurement.doctorDetails == null)
            measurement.doctorDetails = new DoctorDetails();

        // label elements
        showLabelElements(measurement);

        View personalTrackingInfo = findViewById(R.id.personalTrackingInfo);
        personalTrackingInfo.setVisibility(mShowPersonalTrackingInfo ? View.VISIBLE : View.GONE);

        if(mShowPersonalTrackingInfo) {
            SeekBar seekHappiness = (SeekBar) findViewById(R.id.seekHappiness);
            SeekBar seekSleepQuality = (SeekBar) findViewById(R.id.seekSleepQuality);
            seekHappiness.setProgress(getInt(measurement.doctorDetails.happiness));
            seekSleepQuality.setProgress(getInt(measurement.doctorDetails.sleep_quality));
        }

        // form elements
        try {
            details2ui(new JSONObject(measurement.doctorDetails.serialize()));
        } catch (JSONException e) {
            Toast.makeText(EditActivity.this, "Error reading doctorDetails, this should never happen", Toast.LENGTH_LONG).show();
            // this should never happen
            // TODO: proper logging to server
            e.printStackTrace();
        }
    }

    private void showLabelElements(Measurement measurement) {
        MeasurementResult result = measurement.result;

        TextView date = (TextView) findViewById(R.id.date);
        TextView measurementId = (TextView) findViewById(R.id.measurementId);
        TextView heartRate = (TextView) findViewById(R.id.heartRate);
        TextView heartScore = (TextView) findViewById(R.id.heartScore);
        TextView age = (TextView) findViewById(R.id.age);
        TextView gender = (TextView) findViewById(R.id.gender);

        Date timeStamp = new java.util.Date(measurement.startTime * 1000);
        String dateText = mDateFormat.format(timeStamp) + " at " + mTimeFormat.format(timeStamp);
        date.setText(dateText);

        String midText = "?";
        if(result != null && result.token != null)
            midText = result.token;
        measurementId.setText(midText);

        if(result != null)
            heartRate.setText(Integer.toString((int) result.getHeartRate()) + " bpm");
        else
            heartRate.setText("-");

        if(result != null && result.status.equals(MeasurementResult.Status.OK))
            heartScore.setText(Integer.toString((int) (100.0 * result.pred)));
        else
            heartScore.setText("?");

        age.setText(Integer.toString(measurement.user.age));
        gender.setText(measurement.user.gender.toString().toLowerCase());
    }

    /** UI -> Measurement */
    private void updateMeasurement(Measurement measurement) {
        try {
            JSONObject details = ui2details();
            measurement.doctorDetails = DoctorDetails.deserialize(details.toString());
            measurement.doctorDetails.time = System.currentTimeMillis() / 1000;
        } catch (JSONException e) {
            Toast.makeText(EditActivity.this, "Error writing doctorDetails, this should never happen", Toast.LENGTH_LONG).show();
            // this should never happen
            // TODO: proper logging to server
            e.printStackTrace();
        }

        if(mShowPersonalTrackingInfo) {
            SeekBar seekHappiness = (SeekBar) findViewById(R.id.seekHappiness);
            SeekBar seekSleepQuality = (SeekBar) findViewById(R.id.seekSleepQuality);
            measurement.doctorDetails.happiness = seekHappiness.getProgress();
            measurement.doctorDetails.sleep_quality = seekSleepQuality.getProgress();
        }
    }

    private JSONObject ui2details() throws JSONException {

        JSONObject details = new JSONObject();

        for(Element chk : CHECKBOXES) {
            CheckBox checkBox = (CheckBox) findViewById(chk.id);
            details.put(chk.name, checkBox.isChecked());
        }

        for(Element txt : TEXTBOXES) {
            EditText editText = (EditText) findViewById(txt.id);
            details.put(txt.name, editText.getText());
        }

        return details;
    }

    private void details2ui(JSONObject details) throws JSONException {
        for(Element chk : CHECKBOXES) {
            if(!details.has(chk.name))
                continue;
            CheckBox checkBox = (CheckBox) findViewById(chk.id);
            checkBox.setChecked(details.getBoolean(chk.name));
            checkBox.invalidate();
        }

        for(Element txt : TEXTBOXES) {
            if(!details.has(txt.name))
                continue;
            EditText editText = (EditText) findViewById(txt.id);
            editText.setText(details.getString(txt.name));
            editText.invalidate();
        }
    }
}
