package org.deke.risk.riskahead;

import android.app.AlertDialog;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.location.Address;
import android.location.Geocoder;
import android.os.Bundle;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import androidx.core.content.ContextCompat;
import android.util.Log;
import android.view.View;
import android.widget.EditText;

import com.android.volley.Request;
import com.android.volley.toolbox.StringRequest;
import com.beardedhen.androidbootstrap.AwesomeTextView;
import com.beardedhen.androidbootstrap.BootstrapLabel;
import com.google.firebase.crashlytics.FirebaseCrashlytics;
import com.mikepenz.google_material_typeface_library.GoogleMaterial;
import com.mikepenz.iconics.IconicsDrawable;

import org.deke.risk.riskahead.helper.AppConfig;
import org.deke.risk.riskahead.helper.AppController;
import org.deke.risk.riskahead.helper.BaseActivity;
import org.deke.risk.riskahead.helper.IncidentReport;
import org.deke.risk.riskahead.helper.SessionManager;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

/**
 *
 * (C) Copyright 2016 RiskAhead (http://www.riskahead.net)
 * Developer & Contributor: Dennis Thießen (dennis.thiessen@riskahead.net)
 * Date of Release: 10.02.2016
 *
 */
public class ViewReportActivity extends BaseActivity {
    private final static String TAG = ViewReportActivity.class.getSimpleName();

    private EditText txtIncidentCategory;
    private EditText txtIncidentSubCategory;
    private EditText txtPosition;
    private EditText txtTime;
    private EditText txtSuspect;
    private EditText txtWeapons;
    private EditText txtNumOfSuspects;
    private EditText txtVictim;
    private EditText txtVictimOrigin;
    private EditText txtSuspectTransport;
    private EditText txtVictimAffiliation;
    private EditText txtSuspectRecognition;
    private EditText txtEtcEtc;
    private EditText txtReportedFrom;

    private BootstrapLabel scorelabel;
    private IncidentReport incident;

    private AwesomeTextView btnUpvote;
    private AwesomeTextView btnDownvote;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        userHasToBeLoggedIn();

        initViewsAndButtons();
    }

    private void initViewsAndButtons() {
        txtIncidentCategory = findViewById(R.id.txt_viewreport_incidentcategory);
        txtIncidentSubCategory = findViewById(R.id.txt_viewreport_incidentsubcategory);
        txtPosition = findViewById(R.id.txt_viewreport_position);
        txtTime = findViewById(R.id.txt_viewreport_time);
        scorelabel = findViewById(R.id.txt_viewreport_points);
        txtSuspect = findViewById(R.id.txt_viewreport_suspect);
        txtWeapons = findViewById(R.id.txt_viewreport_suspectweapon);
        txtNumOfSuspects = findViewById(R.id.txt_viewreport_suspectcount);
        txtVictim = findViewById(R.id.txt_viewreport_victim);
        txtVictimOrigin = findViewById(R.id.txt_viewreport_victimorigin);
        txtSuspectTransport = findViewById(R.id.txt_viewreport_suspecttransport);
        txtVictimAffiliation = findViewById(R.id.txt_viewreport_victimaff);
        txtSuspectRecognition = findViewById(R.id.txt_viewreport_suspectrecon);
        txtEtcEtc = findViewById(R.id.txt_viewreport_etcetc);
        txtReportedFrom = findViewById(R.id.txt_viewreport_reportedfrom);
        btnUpvote = findViewById(R.id.btn_viewreport_upvote);
        btnDownvote = findViewById(R.id.btn_viewreport_downvote);


        Intent intent = getIntent();
        final Integer id = intent.getIntExtra(BaseActivity.EXTRA_MESSAGE, 0);
        getIncident(id);

        btnUpvote.setOnClickListener(v -> makeUpvote(id));
        findViewById(R.id.layoutFooter).setVisibility(View.GONE);
        btnDownvote.setOnClickListener(v -> makeDownvote(id));

        findViewById(R.id.btn_viewreport_delete).setOnClickListener(v -> new AlertDialog.Builder(ViewReportActivity.this)
                .setTitle(getResources().getString(R.string.txt_viewreport_deletetitle))
                .setMessage(getResources().getString(R.string.txt_viewreport_deletetext))
                .setPositiveButton(android.R.string.yes, (dialog, which) -> deleteReport(id))
                .setNegativeButton(android.R.string.no, (dialog, which) -> {
                    //do nothing
                })
                .setIcon(android.R.drawable.ic_dialog_alert)
                .show());

        Drawable identityIcon = new IconicsDrawable(this)
                .icon(GoogleMaterial.Icon.gmd_account_circle)
                .color(ContextCompat.getColor(getApplicationContext(), R.color.white))
                .sizeDp(24);

        ((FloatingActionButton) findViewById(R.id.btn_viewreport_user)).setImageDrawable(identityIcon);
    }

    private void deleteReport(Integer uid) {
        deleteIncident(uid);
    }

    public void deleteIncident(Integer uid) {
        showDialog();

        String tag_string_req = "deactivateIncident";
        StringRequest strReq = getStringRequestDeleteIncident(uid);
        AppController.getInstance().addToRequestQueue(strReq, tag_string_req);
    }

    private StringRequest getStringRequestDeleteIncident(final Integer incidentid) {
        return new StringRequest(Request.Method.POST, AppConfig.REST_DEACTIVATE_INCIDENT, response -> {
            Log.d(TAG, "Delete Incident with ID response: " + response);
            hideDialog();

            try {
                JSONObject jObj = new JSONObject(response);
                boolean error = jObj.getBoolean("error");

                if (!error) {
                    showMessage(getString(R.string.txt_success_incidentdel));
                    gotoProfileActivity();
                } else {
                    String errorMsg = jObj.getString("error_msg");
                    FirebaseCrashlytics.getInstance().log("Error deleting incident (Server returned error): " + errorMsg);
                    showMessage(getResources().getString(R.string.txt_errormsg_deleteincident));
                }
            } catch (JSONException e) {
                FirebaseCrashlytics.getInstance().log("JSONException caught: " + e);
            }
        }, error -> {
            FirebaseCrashlytics.getInstance().log("Error deleting incident: " + error.getMessage());
            handleVolleyErrorResponse();
            hideDialog();
        }) {

            @Override
            protected Map<String, String> getParams() {
                Map<String, String> params = new HashMap<>();
                params.put("uid", user.get(SessionManager.KEY_UID));
                params.put("token", user.get(SessionManager.TOKEN));
                params.put("incidentid", incidentid.toString());


                return params;
            }
        };
    }

    public void getIncident(Integer uid) {
        showDialog();
        String tag_string_req = "getincidentwithpositionfromid";
        StringRequest strReq = getStringRequestGetIncidentWithPositionFromID(uid);
        AppController.getInstance().addToRequestQueue(strReq, tag_string_req);
    }

    private StringRequest getStringRequestGetIncidentWithPositionFromID(final Integer incidentid) {
        return new StringRequest(Request.Method.POST, AppConfig.REST_GET_INCIDENT, response -> {
            Log.d(TAG, "Incident with ID response: " + response);
            hideDialog();

            try {
                JSONObject jObj = new JSONObject(response);
                boolean error = jObj.getBoolean("error");

                if (!error) {
                    JSONObject jIncident = jObj.getJSONObject("msg");

                    checkVotetypeAndSetVoteButtons(jIncident);
                    initReport(new IncidentReport(jIncident));

                } else {
                    String errorMsg = jObj.getString("error_msg");
                    FirebaseCrashlytics.getInstance().log( "Error get incident (Server returned error): " + errorMsg);
                    showMessage(getResources().getString(R.string.txt_errormsg_getincidentdetail));
                }
            } catch (JSONException e) {
                FirebaseCrashlytics.getInstance().log("JSONException caught: " + e);
            }
        }, error -> {
            FirebaseCrashlytics.getInstance().log("Error get incident: " + error.getMessage());
            handleVolleyErrorResponse();
            hideDialog();
        }) {

            @Override
            protected Map<String, String> getParams() {
                // Posting parameters to login url
                Map<String, String> params = new HashMap<>();
                params.put("uid", user.get(SessionManager.KEY_UID));
                params.put("token", user.get(SessionManager.TOKEN));
                params.put("incidentid", incidentid.toString());


                return params;
            }

        };
    }

    private void checkVotetypeAndSetVoteButtons(final JSONObject jIncident) throws JSONException {
        if (jIncident.has("hasvoted")) {
            if (jIncident.get("hasvoted") instanceof JSONObject) {
                JSONObject hasvoted = jIncident.getJSONObject("hasvoted");

                Log.d(TAG, "hasvote is instance of JSONObject. GO FOR IT");

                if (hasvoted.has("fid_votetype")) {
                    if (hasvoted.getInt("fid_votetype") == AppConfig.VOTETYPE_UPVOTE) {
                        btnUpvote.startFlashing(true, AwesomeTextView.AnimationSpeed.MEDIUM);
                        btnDownvote.startFlashing(false, AwesomeTextView.AnimationSpeed.MEDIUM);

                        btnUpvote.setOnClickListener(v -> deleteVote(incident.getId()));

                        btnDownvote.setOnClickListener(v -> {
                            deleteVote(incident.getId());
                            makeDownvote(incident.getId());
                        });
                    } else if (hasvoted.getInt("fid_votetype") == AppConfig.VOTETYPE_DOWNVOTE) {
                        btnUpvote.startFlashing(false, AwesomeTextView.AnimationSpeed.MEDIUM);
                        btnDownvote.startFlashing(true, AwesomeTextView.AnimationSpeed.MEDIUM);

                        btnUpvote.setOnClickListener(v -> {
                            deleteVote(incident.getId());
                            makeUpvote(incident.getId());
                        });

                        btnDownvote.setOnClickListener(v -> deleteVote(incident.getId()));
                    } else {
                        btnUpvote.startFlashing(false, AwesomeTextView.AnimationSpeed.MEDIUM);
                        btnDownvote.startFlashing(false, AwesomeTextView.AnimationSpeed.MEDIUM);

                        btnUpvote.setOnClickListener(v -> makeUpvote(incident.getId()));

                        btnDownvote.setOnClickListener(v -> makeDownvote(incident.getId()));
                    }
                }
            } else {
                btnUpvote.startFlashing(false, AwesomeTextView.AnimationSpeed.MEDIUM);
                btnDownvote.startFlashing(false, AwesomeTextView.AnimationSpeed.MEDIUM);

                btnUpvote.setOnClickListener(v -> makeUpvote(incident.getId()));

                btnDownvote.setOnClickListener(v -> makeDownvote(incident.getId()));
            }
        }
    }

    private String checkIfTextEmptyAndReturnString(String input) {
        String formattedString = getString(R.string.txt_viewreport_noinput);

        if (input.trim().length() > 0) {
            formattedString = input;
        }

        return formattedString;
    }

    private void initReport(IncidentReport incident) {
        Context tmpContext = getApplicationContext();

        scorelabel.setText(String.format(Locale.US, "%d", incident.getVotedScore()));
        txtIncidentCategory.setText(incident.getIncidentCategoryName(tmpContext));
        txtIncidentSubCategory.setText(checkIfTextEmptyAndReturnString(incident.getIncidentSubCategoryName(tmpContext)));
        txtTime.setText(checkIfTextEmptyAndReturnString(incident.getTimeString(tmpContext)));
        txtSuspect.setText(checkIfTextEmptyAndReturnString(incident.getSuspectString(tmpContext)));
        txtWeapons.setText(checkIfTextEmptyAndReturnString(incident.getSuspectWeaponsString(tmpContext)));
        txtNumOfSuspects.setText(checkIfTextEmptyAndReturnString(incident.getSuspectNoOfString(tmpContext)));
        txtVictim.setText(checkIfTextEmptyAndReturnString(incident.getVictimString(tmpContext)));
        txtVictimOrigin.setText(checkIfTextEmptyAndReturnString(incident.getVictimOriginString(tmpContext)));
        txtSuspectTransport.setText(checkIfTextEmptyAndReturnString(incident.getSuspectTransportString(tmpContext)));
        txtVictimAffiliation.setText(checkIfTextEmptyAndReturnString(incident.getVictimAffiliationString(tmpContext)));
        txtSuspectRecognition.setText(checkIfTextEmptyAndReturnString(incident.getSuspectRecognitionString(tmpContext)));
        txtEtcEtc.setText(checkIfTextEmptyAndReturnString(incident.getEtcOthersCategory()));
        txtReportedFrom.setText(incident.getFromUsername());

        this.incident = incident;

        Geocoder geocoder = new Geocoder(getApplicationContext(), Locale.getDefault());

        try {
            List<Address> addressList = geocoder.getFromLocation(incident.getPosition().latitude, incident.getPosition().longitude, 1);
            if (addressList != null && addressList.size() > 0) {
                Address address = addressList.get(0);
                StringBuilder sb = new StringBuilder();

                for (int i = 0; i < address.getMaxAddressLineIndex(); i++) {
                    if (address.getAddressLine(i) != null)
                        sb.append(address.getAddressLine(i)).append("\n");
                }

                if (address.getCountryName() != null) sb.append(address.getCountryName());

                txtPosition.setText(sb.toString());
            }
        } catch (IOException e) {
            FirebaseCrashlytics.getInstance().log("IOException caught: " + e);
        }

        final String latitude = Double.toString(incident.getPosition().latitude);
        final String longitude = Double.toString(incident.getPosition().longitude);
        final String fromUid = Integer.toString(incident.getFidFromUser());

        findViewById(R.id.btn_viewreport_user).setOnClickListener(v -> gotoProfileActivity(fromUid));

        findViewById(R.id.btn_viewreport_position).setOnClickListener(v -> gotoMapActivity(latitude + ":" + longitude));

        String uid = user.get(SessionManager.KEY_UID);
        if (incident.getFidFromUser() != Integer.parseInt(uid)) {
            findViewById(R.id.layoutFooter).setVisibility(View.GONE);
        } else {
            findViewById(R.id.layoutFooter).setVisibility(View.VISIBLE);
        }
    }

    public void makeUpvote(Integer incidentid) {
        if (user.get(SessionManager.KEY_UID).equals(Integer.toString(incident.getFidFromUser()))) {
            showMessage(getResources().getString(R.string.txt_errormsg_cannotvoteowninc));
        } else {
            String tag_string_req = "addvote";
            StringRequest strReq = getStringRequestAddVote(incidentid, "1");
            AppController.getInstance().addToRequestQueue(strReq, tag_string_req);
        }
    }

    public void makeDownvote(Integer incidentid) {
        if (user.get(SessionManager.KEY_UID).equals(Integer.toString(incident.getFidFromUser()))) {
            showMessage(getResources().getString(R.string.txt_errormsg_cannotvoteowninc));
        } else {
            String tag_string_req = "addvote";
            StringRequest strReq = getStringRequestAddVote(incidentid, "2");
            AppController.getInstance().addToRequestQueue(strReq, tag_string_req);
        }
    }

    private StringRequest getStringRequestAddVote(final Integer incidentid, final String votetype) {
        return new StringRequest(Request.Method.POST, AppConfig.REST_ADD_VOTE, response -> {
            Log.d(TAG, "MadeVote: " + response);

            try {
                JSONObject jObj = new JSONObject(response);
                boolean error = jObj.getBoolean("error");

                if (!error) {
                    showMessage(getString(R.string.txt_success_voted));
                    JSONObject jPoints = jObj.getJSONObject("points");

                    scorelabel.setText(String.format(Locale.US, "%d",jPoints.getInt("upvoted") - jPoints.getInt("downvoted")));
                    checkVotetypeAndSetVoteButtons(jPoints);
                } else {
                    String errorMsg = jObj.getString("error_msg");
                    FirebaseCrashlytics.getInstance().log("Error voting incident (Server returned error): " + errorMsg);
                    showMessage(getResources().getString(R.string.txt_errormsg_couldnotvote));
                }
            } catch (JSONException e) {
                FirebaseCrashlytics.getInstance().log("JSONException caught: " + e);
            }
        }, error -> {
            FirebaseCrashlytics.getInstance().log("Error voting incident: " + error.getMessage());
            handleVolleyErrorResponse();
        }) {

            @Override
            protected Map<String, String> getParams() {
                Map<String, String> params = new HashMap<>();
                params.put("uid", user.get(SessionManager.KEY_UID));
                params.put("token", user.get(SessionManager.TOKEN));
                params.put("incidentid", incidentid.toString());
                params.put("votetype", votetype);

                return params;
            }
        };
    }

    public void deleteVote(Integer incidentid) {
        String tag_string_req = "deletevote";
        StringRequest strReq = getStringRequestDeleteVote(incidentid);
        AppController.getInstance().addToRequestQueue(strReq, tag_string_req);
    }

    private StringRequest getStringRequestDeleteVote(final Integer incidentid) {
        return new StringRequest(Request.Method.POST, AppConfig.REST_DELETE_VOTE, response -> {
            Log.d(TAG, "Delete Vote: " + response);

            try {
                JSONObject jObj = new JSONObject(response);
                boolean error = jObj.getBoolean("error");

                if (!error) {
                    JSONObject jPoints = jObj.getJSONObject("points");

                    scorelabel.setText(String.format(Locale.US, "%d", jPoints.getInt("upvoted") - jPoints.getInt("downvoted")));
                    checkVotetypeAndSetVoteButtons(jPoints);
                } else {
                    String errorMsg = jObj.getString("error_msg");
                    FirebaseCrashlytics.getInstance().log("Error deleting voting incident (Server returned error): " + errorMsg);
                }
            } catch (JSONException e) {
                FirebaseCrashlytics.getInstance().log("JSONException caught");
                FirebaseCrashlytics.getInstance().recordException(e);
            }
        }, error -> {
            FirebaseCrashlytics.getInstance().log("Error deleting voting incident: " + error.getMessage());
            handleVolleyErrorResponse();
        }) {

            @Override
            protected Map<String, String> getParams() {
                Map<String, String> params = new HashMap<>();
                params.put("uid", user.get(SessionManager.KEY_UID));
                params.put("token", user.get(SessionManager.TOKEN));
                params.put("incidentid", incidentid.toString());

                return params;
            }
        };
    }

    @Override
    protected int getLayoutResourceId() {
        return R.layout.activity_view_report;
    }

    @Override
    protected String getActivityName() {
        return getResources().getString(R.string.title_activity_view_report);
    }
}
