package org.deke.risk.riskahead;

import android.Manifest;
import android.app.AlertDialog;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.provider.MediaStore;
import androidx.core.app.ActivityCompat;
import androidx.fragment.app.FragmentTransaction;
import android.content.Intent;
import android.content.SharedPreferences;
import android.location.Address;
import android.location.Geocoder;
import android.os.Bundle;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;

import com.android.volley.Request;
import com.android.volley.toolbox.StringRequest;
import com.beardedhen.androidbootstrap.BootstrapButton;
import com.beardedhen.androidbootstrap.api.defaults.DefaultBootstrapBrand;
import com.google.android.gms.maps.model.LatLng;
import com.google.firebase.crashlytics.FirebaseCrashlytics;
import com.google.gson.Gson;

import org.deke.risk.riskahead.fragment.BaseReportWFFragment;
import org.deke.risk.riskahead.fragment.ReportWF_1_Fragment;
import org.deke.risk.riskahead.fragment.ReportWF_2_Fragment;
import org.deke.risk.riskahead.fragment.ReportWF_3_Fragment;
import org.deke.risk.riskahead.fragment.ReportWF_4_Fragment;
import org.deke.risk.riskahead.fragment.ReportWF_5_Fragment;
import org.deke.risk.riskahead.fragment.ReportWF_6_Fragment;
import org.deke.risk.riskahead.fragment.ReportWF_7_Fragment;
import org.deke.risk.riskahead.fragment.ReportWF_8_Fragment;
import org.deke.risk.riskahead.fragment.ReportWF_Finish_Fragment;
import org.deke.risk.riskahead.helper.IncidentReport;
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.SessionManager;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.util.ArrayList;
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 ReportWFActivity extends BaseActivity implements ReportWF_1_Fragment.OnInputFinishedListener, ReportWF_2_Fragment.OnInputFinishedListener, ReportWF_3_Fragment.OnInputFinishedListener
                                                                ,ReportWF_4_Fragment.OnInputFinishedListener, ReportWF_5_Fragment.OnInputFinishedListener,ReportWF_6_Fragment.OnInputFinishedListener
                                                                ,ReportWF_7_Fragment.OnInputFinishedListener, ReportWF_8_Fragment.OnInputFinishedListener, ReportWF_Finish_Fragment.SendReportListener {

    private final static String TAG = ReportWFActivity.class.getSimpleName();
    private static final int MY_PERMISSIONS_REQUEST_STORAGE = 42;

    private List<BaseReportWFFragment> fragList = new ArrayList<>();

    private BaseReportWFFragment frag_report_1 = new ReportWF_1_Fragment();
    private BaseReportWFFragment frag_report_2 = new ReportWF_2_Fragment();
    private BaseReportWFFragment frag_report_3 = new ReportWF_3_Fragment();
    private BaseReportWFFragment frag_report_4 = new ReportWF_4_Fragment();
    private BaseReportWFFragment frag_report_5 = new ReportWF_5_Fragment();
    private BaseReportWFFragment frag_report_6 = new ReportWF_6_Fragment();
    private BaseReportWFFragment frag_report_7 = new ReportWF_7_Fragment();
    private BaseReportWFFragment frag_report_8 = new ReportWF_8_Fragment();
    private BaseReportWFFragment frag_report_finish = new ReportWF_Finish_Fragment();

    private BootstrapButton btnContinue;
    private BootstrapButton btnReportNow;
    private FloatingActionButton btnMap;
    private TextView siteIndicator;

    private IncidentReport incident = new IncidentReport();

    private int currentState = 0;

    public boolean resetSignal = false;

    private SharedPreferences mPrefs;
    private SharedPreferences.Editor prefsEditor;

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

        initFragments();
        initButtonsAndElements();

        mPrefs = getPreferences(MODE_PRIVATE);
        prefsEditor = mPrefs.edit();
    }

    private void initFragments() {
        fragList.add(frag_report_1);
        fragList.add(frag_report_2);
        fragList.add(frag_report_3);
        fragList.add(frag_report_4);
        fragList.add(frag_report_5);
        fragList.add(frag_report_6);
        fragList.add(frag_report_7);
        fragList.add(frag_report_8);
        fragList.add(frag_report_finish);
    }

    private void initButtonsAndElements() {
        btnContinue = findViewById(R.id.btn_reportwf_next);
        btnContinue.setEnabled(false);
        btnContinue.setOnClickListener(v -> {
            incident = fragList.get(currentState).getCurrentInput();
            initFragment(currentState + 1);
        });

        btnReportNow = findViewById(R.id.btn_reportwf_reportnow);
        btnReportNow.setEnabled(false);
        btnReportNow.setOnClickListener(v -> {
            incident = fragList.get(currentState).getCurrentInput();
            sendReport();
        });

        siteIndicator = findViewById(R.id.lbl_reportwf_site);

        btnMap = findViewById(R.id.fab_reportwf_map);
        btnMap.setOnClickListener(v -> {
            incident = fragList.get(currentState).getCurrentInput();
            if (incident != null && incident.getPosition() != null) {
                getIncidentLocationFromMapActivity(incident.getPosition().latitude + ":" + incident.getPosition().longitude);
            } else {
                getIncidentLocationFromMapActivity();
            }
        });
    }

    private void initFragment(int state) {
        findViewById(R.id.atvStatus).setVisibility(View.INVISIBLE);
        currentState = state;

        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
        transaction.replace(R.id.fragment_reportwf, fragList.get(state));
        transaction.commit();

        if(state > 0){
            btnMap.setVisibility(View.GONE);
        }

        if(state == (fragList.size()-1)){
            btnContinue.setEnabled(false);
            btnReportNow.setEnabled(false);
            siteIndicator.setVisibility(View.INVISIBLE);
        }else{
            siteIndicator.setVisibility(View.VISIBLE);
        }

        String currentSite = (currentState+1) + "/" + (fragList.size()-1);
        siteIndicator.setText(currentSite);

    }

    private void resetStateAndIncident(){
        resetSignal = true;
        currentState = 0;
        incident = new IncidentReport();

        prefsEditor.remove("incident");
        prefsEditor.remove("currentState");
        prefsEditor.commit();
    }

    private void modifyPos(String pos){
            String[] position = pos.split(":");
            Geocoder geocoder = new Geocoder(getApplicationContext(), Locale.getDefault());
            LatLng latlngpos = new LatLng(
                    Double.parseDouble(position[0]),
                    Double.parseDouble(position[1]));
            incident.setPosition(latlngpos);

            try {
                List<Address> addressList = geocoder.getFromLocation(latlngpos.latitude,latlngpos.longitude,1);

                if (addressList != null && addressList.size() > 0) {
                    Address address = addressList.get(0);

                    if(address.getAddressLine(0) != null){
                        incident.setIncidentPositionDescription(
                                address.getAddressLine(0).replace(", ", "\n"));
                    }
                }
            } catch (IOException e) {
                FirebaseCrashlytics.getInstance().log("JSONException caught: " + e);
                incident.setIncidentPositionDescription("Latitude: " + latlngpos.latitude + "\nLongitude: " + latlngpos.longitude);
            }
    }

    @Override
    public void sendReport() {
        incident = fragList.get(currentState).getCurrentInput();

        String tag_string_req = "addincidentwithposition";
        StringRequest strReq = getStringRequestAddIncidentWithPosition(incident);
        AppController.getInstance().addToRequestQueue(strReq, tag_string_req);
    }


    public void setIncident(IncidentReport newIncident){
        if(!resetSignal){
            incident = newIncident;
            Gson gson = new Gson();
            Log.d(this.getActivityName(),"Set Incident with CurrentState: "+currentState+" / Details: "+gson.toJson(incident));
        }
    }

    public IncidentReport getIncident(){
        return incident;
    }

    @Override
    public void onInputFinished(boolean finished) {
        if(finished) {
            findViewById(R.id.atvStatus).setVisibility(View.VISIBLE);
            btnContinue.setBootstrapBrand(DefaultBootstrapBrand.SUCCESS);

        }else{
            findViewById(R.id.atvStatus).setVisibility(View.INVISIBLE);
            btnContinue.setBootstrapBrand(DefaultBootstrapBrand.REGULAR);
        }

        if((currentState == 1 && finished) || (currentState > 1)){
            btnReportNow.setEnabled(true);
        }else{
            btnReportNow.setEnabled(false);
        }

        if(finished || currentState > 1){
            btnContinue.setEnabled(true);
        }else{
            btnContinue.setEnabled(false);
        }
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();

        if((id == R.id.menu_btn_gotostart)){
            new AlertDialog.Builder(ReportWFActivity.this)
                    .setTitle(getResources().getString(R.string.txt_reportwf_newincidenttitle))
                    .setMessage(getResources().getString(R.string.txt_reportwf_newincidenttext))
                    .setPositiveButton(android.R.string.yes, (dialog, which) -> {
                        resetStateAndIncident();
                        initFragment(0);

                        if(currentState == 0){
                            gotoReportActivity();
                        }
                    })
                    .setNegativeButton(android.R.string.no, (dialog, which) -> {
                        // do nothing
                    })
                    .setIcon(android.R.drawable.ic_dialog_alert)
                    .show();
        }

        return super.onOptionsItemSelected(item);
    }

    public void setMapButtonVisibility(boolean isVisible){
        if(isVisible){
            btnMap.setVisibility(View.VISIBLE);
        }else{
            btnMap.setVisibility(View.INVISIBLE);
        }
    }

    @Override
    public void onBackPressed(){
        if(currentState > 0) {
            initFragment(currentState - 1);
        }else{
            super.onBackPressed();
        }
    }

    private StringRequest getStringRequestAddIncidentWithPosition(final IncidentReport incident) {
        showDialog();
        return new StringRequest(Request.Method.POST, AppConfig.REST_ADD_INCIDENT_WITHPOSITION, response -> {
            Log.d(TAG, "Report response: " + response);

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

                if (!error) {
                    showMessage(getString(R.string.txt_success_addreport));
                    showShareDialog(incident);
                } else {
                    String errorMsg = jObj.getString("error_msg");
                    FirebaseCrashlytics.getInstance().log("Error adding incident (Server returned error): " + errorMsg);
                    showMessage(getResources().getString(R.string.txt_errormsg_createincident));
                }
            } catch (JSONException e) {
                FirebaseCrashlytics.getInstance().log("JSONException caught: " + e);
            }

            hideDialog();
        }, error -> {
            FirebaseCrashlytics.getInstance().log("Error adding 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("latitude", Double.toString(incident.getPosition().latitude));
                params.put("longitude", Double.toString(incident.getPosition().longitude));
                params.put("fid_incident", Integer.toString(incident.getFidIncidentCategory()));
                params.put("fid_subincident", Integer.toString(incident.getFidIncidentSubCategory()));
                params.put("etc_incident", incident.getEtcIncidentCategory());
                params.put("fid_time", Integer.toString(incident.getFidTimeCategory()));
                params.put("fid_subtime", Integer.toString(incident.getFidTimeSubCategory()));
                params.put("happened_from_datetime", incident.getFromDate()+" "+incident.getFromTime());
                params.put("happened_to_datetime", incident.getToDate()+" "+incident.getToTime());
                params.put("fid_suspect", Integer.toString(incident.getFidSuspectCategory()));
                params.put("fid_subsuspect", Integer.toString(incident.getFidSuspectSubCategory()));
                params.put("etc_suspect", incident.getEtcSuspectCategory());
                params.put("fid_weapon", Integer.toString(incident.getFidSuspectWeaponCategory()));
                params.put("fid_subweapon", Integer.toString(incident.getFidSuspectWeaponSubCategory()));
                params.put("etc_weapon", incident.getEtcSuspectWeaponCategory());
                params.put("fid_suspectcount", Integer.toString(incident.getFidSuspectCountCategory()));
                params.put("etc_suspectcount", incident.getEtcSuspectCountCategory());
                params.put("fid_victim", Integer.toString(incident.getFidVictimCategory()));
                params.put("fid_victimorigin", Integer.toString(incident.getFidVictimOriginCategory()));
                params.put("etc_victimorigin", incident.getEtcVictimOriginCategory());
                params.put("fid_suspecttransportation", Integer.toString(incident.getFidSuspectTransportationCategory()));
                params.put("etc_suspecttransportation", incident.getEtcSuspectTransportationCategory());
                params.put("fid_victimbelonging", Integer.toString(incident.getFidVictimBelongingCategory()));
                params.put("etc_victimbelonging", incident.getEtcVictimBelongingCategory());
                params.put("fid_suspectcharacteristics", Integer.toString(incident.getFidSuspectCharacteristicsCategory()));
                params.put("etc_suspectcharacteristics", incident.getEtcSuspectCharacteristicsCategory());
                params.put("fid_others", Integer.toString(incident.getFidOthersCategory()));
                params.put("etc_others", incident.getEtcOthersCategory());

                return params;
            }
        };
    }

    private void requestPermission(){
        ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, MY_PERMISSIONS_REQUEST_STORAGE);
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        switch (requestCode) {
            case MY_PERMISSIONS_REQUEST_STORAGE: {
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    startShareIncidentIntent(incident);
                } else {
                    finishReportAndGotoMap(incident);
                }
            }
        }
    }

    private void showShareDialog(final IncidentReport incident) {
        new AlertDialog.Builder(ReportWFActivity.this)
                .setTitle(R.string.txt_share_title)
                .setMessage(R.string.txt_share_message)
                .setPositiveButton(android.R.string.yes, (dialog, which) -> startShareIncidentIntent(incident))
                .setNegativeButton(android.R.string.no, (dialog, which) -> finishReportAndGotoMap(incident))
                .setIcon(android.R.drawable.ic_dialog_alert)
                .show();

    }

    private void startShareIncidentIntent(IncidentReport incident) {
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {

            AlertDialog alertDialog = new AlertDialog.Builder(this).create();
            alertDialog.setTitle("Request Permission");
            alertDialog.setMessage("If you want to use the sharing feature in the future we need storage permission to generate the message which should be shared.");
            alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, "OK",
                    (dialog, which) -> {
                        dialog.dismiss();
                        requestPermission();
                    });
            alertDialog.show();

        }else{
            resetStateAndIncident();
            gotoMapActivity(incident.getPosition().latitude + ":" + incident.getPosition().longitude);

            Intent sharingIntent = new Intent(Intent.ACTION_SEND);
            Bitmap icon = BitmapFactory.decodeResource(getApplicationContext().getResources(),
                    R.drawable.ra_qrcode);

            String[] posDesc = incident.getIncidentPositionDescription().split("\\n");
            String locationText = "";

            if(posDesc.length > 1){
                locationText = posDesc[0] + " - " +posDesc[1];
            }else if(posDesc.length == 1){
                locationText = posDesc[0];
            }else{
               Log.e(TAG, "Could not find location desciption");
            }

            String text = getString(R.string.txt_share_hint)
                    +getString(R.string.txt_share_hint2)+": "+ incident.getIncidentCategoryName(getApplicationContext())
                    +" - "+incident.getIncidentSubCategoryName(getApplicationContext())+"\n"
                    +getString(R.string.txt_share_hint3)+": "+ locationText + "\n"
                    +getString(R.string.txt_share_page);

            sharingIntent.putExtra(Intent.EXTRA_TEXT, text);
            sharingIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse(MediaStore.Images.Media.insertImage(getApplicationContext().getContentResolver(), icon, "Share incident", null)));
            sharingIntent.setType("image/*");
            sharingIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            startActivity(Intent.createChooser(sharingIntent, getString(R.string.txt_share_acttitle)));
        }
    }

    private void finishReportAndGotoMap(IncidentReport incident) {
        resetStateAndIncident();
        gotoMapActivity(incident.getPosition().latitude + ":" + incident.getPosition().longitude);
    }

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

        Gson gson = new Gson();
        String tmpString = mPrefs.getString("incident", "");

        if(tmpString != null && !tmpString.equals("")) incident = gson.fromJson(tmpString, IncidentReport.class);

        Intent intent = getIntent();
        String pos = intent.getStringExtra(EXTRA_MESSAGE);

        if(pos != null) modifyPos(pos);

        currentState = mPrefs.getInt("currentState",0);
        initFragment(currentState);

        navDrawer.setSelection(reportAvtivityID, false);
    }


    @Override
    public void onStop(){
        super.onStop();

        if(!resetSignal){
            Gson gson = new Gson();
            prefsEditor.putString("incident", gson.toJson(incident));
            prefsEditor.putInt("currentState", currentState);
            prefsEditor.commit();
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_reportwf, menu);
        getMenuInflater().inflate(R.menu.menu_common, menu);

        return true;
    }

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

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