package net.heartshield.prevent;

import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.os.Bundle;
import android.text.format.DateFormat;
import android.text.method.LinkMovementMethod;
import android.view.View;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import com.github.mikephil.charting.charts.LineChart;

import net.heartshield.data.DataManagerFactory;
import net.heartshield.data.IMeasurementDataManager;
import net.heartshield.data.Measurement;
import net.heartshield.data.MeasurementId;
import net.heartshield.data.MeasurementResult;
import net.heartshield.data.UserMeta;
import net.heartshield.signal.DVec;
import net.heartshield.ui.LineChartWrapper;

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

/**
 * Result screen showing risk score and various parameters: HRV metrics, pulse shape...
 *
 * @author David Madl (git@abanbytes.eu)
 * @date 2017-04-10
 */
public class ResultActivity extends Activity {
    private static final String TAG = "ResultActivity";
    private IMeasurementDataManager mDataManager;
    private Measurement mMeasurement;

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

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

    public void sendMail(View view) {
        EditText emailText = (EditText) findViewById(R.id.email);
        CheckBox notifyBetaCheckBox = (CheckBox) findViewById(R.id.notifyBeta);
        final String email = emailText.getText().toString();
        final boolean notify = notifyBetaCheckBox.isChecked();
        if(!email.equals("")) {
            Toast.makeText(ResultActivity.this, "Sending mail to: " + email, Toast.LENGTH_LONG).show();
            mMeasurement.user.email = email;
            mMeasurement.user.notifyBeta = notify;

            FancyButton sendButton = (FancyButton) findViewById(R.id.sendButton);
            sendButton.setEnabled(false);

            mDataManager.email(mMeasurement, new IMeasurementDataManager.MeasurementResultListener() {
                @Override
                public void onResult(Measurement measurement) {
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            Toast.makeText(ResultActivity.this, "Result sent to: " + email, Toast.LENGTH_LONG).show();
                        }
                    });
                }

                @Override
                public void onError(Measurement measurement, final IMeasurementDataManager.ErrorCode code, final String message) {
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            Toast.makeText(ResultActivity.this, "Failed to mail result: " + code + " " + message, Toast.LENGTH_LONG).show();
                        }
                    });
                }
            });
        }
    }

    public void measureAgain(View view) {
        Class<?> target;

        if((mMeasurement.hasResult() && mMeasurement.result.status == MeasurementResult.Status.UNCLASSIFIED) || mMeasurement.result.status == MeasurementResult.Status.RECORDED) {
            // repeat measurement, from UNCLASSIFIED result, skip entry of age and gender
            target = MeasureActivity.class;
        } else {
            // new measurement
            target = EnterAgeActivity.class;
        }

        Intent intent = new Intent(ResultActivity.this, target);
        UserMeta meta = mMeasurement.user;
        intent.putExtra("meta", meta);
        intent.putExtra("mode", mMeasurement.meta.mode);
        startActivity(intent);
        mMeasurement = null;
    }

    public void edit(View view) {
        Intent intent = new Intent(ResultActivity.this, EditActivity.class);
        intent.putExtra("measurementId", mMeasurement.getId());
        startActivity(intent);
    }

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

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

        EditText emailText = (EditText) findViewById(R.id.email);
        CheckBox notifyBetaCheckBox = (CheckBox) findViewById(R.id.notifyBeta);
        FancyButton sendButton = (FancyButton) findViewById(R.id.sendButton);

        emailText.setText("");
        notifyBetaCheckBox.setChecked(false);
        sendButton.setEnabled(true);

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

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

        showMeasurement(measurement);

        FancyButton measureAgainButton = (FancyButton) findViewById(R.id.measureAgain);
        if(mMeasurement.hasResult() && mMeasurement.result.status == MeasurementResult.Status.UNCLASSIFIED) {
            // measure again with UNCLASSIFIED result? skip entry of age and gender
            measureAgainButton.setText(getString(R.string.measure_repeat));
        } else {
            measureAgainButton.setText(getString(R.string.measure_new));
        }

        mDataManager.startBackgroundThread();
        mDataManager.startBackgroundSync();
    }

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

    private static final float LINE_WIDTH = 1.0f;
    private static final int LINE_COLOR = Color.BLACK;

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

    private void showMeasurement(Measurement measurement) {
        View scoreBox = (View) findViewById(R.id.heartScoreBox);
        View details = (View) findViewById(R.id.details);
        ImageView resultImage = (ImageView) findViewById(R.id.heartScoreImage);
        ImageView riskReportImage = (ImageView) findViewById(R.id.riskReportImage);
        TextView measurementIdText = (TextView) findViewById(R.id.measurementId);
        TextView disclaimer = (TextView) findViewById(R.id.disclaimer);
        TextView heartScore = (TextView) findViewById(R.id.heartScore);
        TextView heartScoreTitle = (TextView) findViewById(R.id.heartScoreTitle);
        TextView heartScoreDesc = (TextView) findViewById(R.id.heartScoreDesc);
        TextView heartRate = (TextView) findViewById(R.id.heartRate);
        TextView date = (TextView) findViewById(R.id.date);
        TextView date2 = (TextView) findViewById(R.id.date2);
        TextView whatNow = (TextView) findViewById(R.id.whatNow);
        TextView heartRateVariability = (TextView) findViewById(R.id.heartRateVariability);
        //LineChartWrapper chart = new LineChartWrapper((LineChart) findViewById(R.id.chart), LINE_WIDTH, LINE_COLOR);
        FancyButton editButton = (FancyButton) findViewById(R.id.editButton);

        MeasurementResult result = measurement.result;

        int level = 0; // 0-3, 0 is unknown
        int[] backgroundRes = {
                R.color.background_risk_unknown,
                R.color.background_risk_low,
                R.color.background_risk_medium,
                R.color.background_risk_high
        };
        int[] descRes = {
                R.string.desc_risk_unknown,
                R.string.desc_risk_low,
                R.string.desc_risk_medium,
                R.string.desc_risk_high
        };
        int[] titleRes = {
                R.string.title_risk_unknown,
                R.string.title_risk_low,
                R.string.title_risk_medium,
                R.string.title_risk_high
        };
        int[] whatRes = {
                R.string.whatnow_risk_unknown,
                R.string.whatnow_risk_low,
                R.string.whatnow_risk_medium,
                R.string.whatnow_risk_high
        };
        // heartIconRes should be consistent with ResultLineAdapter
        int[] heartIconRes = {
                R.drawable.help_small, // should be consistent with ResultListActivity -> ResultLineAdapter
                R.drawable.heart_ok,
                R.drawable.heart_only,
                R.drawable.heart_nok
        };
        int[] disclaimerRes = {
                R.string.disclaimer2_low, // unused
                R.string.disclaimer2_low,
                R.string.disclaimer2_risk,
                R.string.disclaimer2_risk
        };
        //int bg = ContextCompat.getColor(this, backgroundRes[level]);
        scoreBox.setBackgroundResource(backgroundRes[level]);
        heartScoreDesc.setText(getText(descRes[level]));
        heartScoreTitle.setText(getText(titleRes[level]));
        whatNow.setText(getText(whatRes[level]));
        whatNow.setMovementMethod(LinkMovementMethod.getInstance()); // clickable links (mailto)

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

        measurementIdText.setVisibility(View.GONE);

        if(result == null) {
            resultImage.setImageResource(R.drawable.offline);
            resultImage.invalidate();
            heartRate.setText("Heart rate: -");
            heartRateVariability.setText("");
            heartScore.setText("HeartShield Score: ?");
            whatNow.setText(getText(R.string.whatnow_offline));
            details.setVisibility(View.GONE);
            disclaimer.setVisibility(View.GONE);
            return;
        } else if(result.status == MeasurementResult.Status.UNCLASSIFIED || result.status == MeasurementResult.Status.RECORDED) {
            int img = result.status == MeasurementResult.Status.UNCLASSIFIED ? R.drawable.help_small : R.drawable.heart_only;
            resultImage.setImageResource(img); // should be consistent with ResultListActivity -> ResultLineAdapter
            resultImage.invalidate();
            heartRate.setText("Heart rate: -");
            heartRateVariability.setText("");
            heartScore.setText("HeartShield Score: ?");
            details.setVisibility(View.VISIBLE);
            showChart(result);
            disclaimer.setVisibility(View.GONE);
            if(result.status == MeasurementResult.Status.RECORDED)
                whatNow.setText(result.reason);
            return;
        }

        details.setVisibility(View.VISIBLE);
        disclaimer.setVisibility(View.VISIBLE);

        /*
        final int GREENISH = Color.rgb(0, 204, 0);
        final int REDDISH = Color.rgb(204, 96, 0);
        */

        level = measurement.getRiskLevel();

        scoreBox.setBackgroundResource(backgroundRes[level]);
        heartScoreDesc.setText(getText(descRes[level]));
        heartScoreTitle.setText(getText(titleRes[level]));
        whatNow.setText(getText(whatRes[level]));

        disclaimer.setText(getText(disclaimerRes[level]));

        resultImage.setImageResource(heartIconRes[level]);
        resultImage.invalidate();
        heartScore.setText("HeartShield Score: " + Integer.toString((int) (100.0 * result.pred)));
        //heartScore.setTextColor(result.isHealthy() ? GREENISH : REDDISH);

        if(result.token != null) {
            measurementIdText.setVisibility(View.VISIBLE);
            measurementIdText.setText(String.format(Locale.getDefault(), "Measurement ID: %s", result.token));
        }

        heartRate.setText(String.format(Locale.getDefault(), "Heart rate: %d", (int) result.getHeartRate()));

        heartRateVariability.setText(String.format(Locale.getDefault(), HRV_TEMPLATE,
                result.hrvTimeDomain.sdnn,
                result.hrvTimeDomain.rmssd,
                result.hrvTimeDomain.pnn50,
                result.hrvTimeDomain.hrv_tri,
                decRound(result.hrvFrequencyDomain.total_power, 1),
                decRound(result.hrvFrequencyDomain.lf, 1),
                decRound(result.hrvFrequencyDomain.hf, 1),
                result.hrvFrequencyDomain.lf / result.hrvFrequencyDomain.hf));

        showChart(result);

        Bitmap reportImage = mDataManager.getReportImage(measurement.getId());
        if(reportImage != null)
            riskReportImage.setImageBitmap(reportImage);
        else
            riskReportImage.setImageResource(0);
    }

    private void showChart(MeasurementResult result) {
        LineChartWrapper chart = new LineChartWrapper((LineChart) findViewById(R.id.chart), LINE_WIDTH, LINE_COLOR);

        double[] fakeTimes = DVec.linspace(0, LineChartWrapper.WINDOW_SIZE_SECS, result.filtered.length);

        double[] adjusted = result.filtered;
        adjusted = DVec.mul(adjusted, -1.0);
        adjusted = DVec.sub(adjusted, DVec.min(adjusted));
        adjusted = DVec.mul(adjusted, 0.9 / DVec.max(adjusted));
        adjusted = DVec.add(adjusted, 0.1);
        for(int i = 0; i < result.idx.length; i++)
            adjusted[result.idx[i]] = 0.0;

        chart.replaceData(fakeTimes, adjusted);
    }

    private static final String HRV_TEMPLATE = "" +
            "SDNN: %.0f ms\n" +
            "RMSSD: %.0f ms\n" +
            "PNN50: %.0f %%\n" +
            "HRV triangular index: %.1f\n" +
            "total power: %.0f ms^2\n" +
            "LF: %.0f ms^2\n" +
            "HF: %.0f ms^2\n" +
            "LF/HF ratio: %.2f\n";

    private static double decRound(double d, int digits) {
        double fac = Math.pow(10.0, digits);
        return Math.round(d / fac) * fac;
    }
}
