package org.keyscience.Services;

import android.app.IntentService;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.NotificationManagerCompat;
import android.support.v4.content.ContextCompat;
import android.support.v4.content.LocalBroadcastManager;
import android.text.TextUtils;
import android.util.Log;

import com.google.android.gms.location.Geofence;
import com.google.android.gms.location.GeofencingEvent;

import org.keyscience.Database.DatabaseHelper;
import org.keyscience.Database.EcoQuestDBContract;
import org.keyscience.R;
import org.keyscience.SingletonPattern.SingletonEcoQuests;
import org.keyscience.SingletonPattern.User;
import org.keyscience.app.Constants;
import org.keyscience.app.EcoQuestInfoActivity;
import org.keyscience.models.EcoQuestModel;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * An {@link IntentService} subclass for handling asynchronous task requests in
 * a service on a separate handler thread.
 */
public class GeofenceTransitionsIntentService extends IntentService {
    private static final String CHANNEL_ID = "GeoFence";
    private static final String CHANNEL_NAME = "EcoQuest Notifications";
    private static final String CHANNEL_DESCRIPTION = "User is notified when entering an EcoQuest zone.";

    public GeofenceTransitionsIntentService() {
        super("GeofenceTransitionsIntentService");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
        if (geofencingEvent.hasError()) {
            return;
        }

        // Get the transition type.
        int geofenceTransition = geofencingEvent.getGeofenceTransition();

        // Test that the reported transition was of interest.
        if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER ||
                geofenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT) {

            // Get the geofences that were triggered. A single event can trigger
            // multiple geofences.
            List<Geofence> triggeringGeofences = geofencingEvent.getTriggeringGeofences();

            // Send notification and log the transition details.
            createNotificationChannel();
            sendNotification(triggeringGeofences.get(0).getRequestId());

            // update user points and geofence status for user
            int ecoQuestID = Integer.parseInt(triggeringGeofences.get(0).getRequestId());
            SingletonEcoQuests singletonEcoQuests = SingletonEcoQuests.getInstance();
            EcoQuestModel ecoQuestModel = singletonEcoQuests.getHashMap().get(ecoQuestID);

            DatabaseHelper databaseHelper = new DatabaseHelper(getApplicationContext());

            //if ecoquest is completed for the first time
            if (!User.getInstance().contains(ecoQuestID)) {
                User.getInstance().addCompletedQuest(ecoQuestID);
                User.getInstance().setPoints(User.getInstance().getPoints() + ecoQuestModel.getPoints());

                // refresh UI to reflect points
                Intent intentRefreshUI = new Intent();
                intentRefreshUI.setAction(Constants.REFRESH_USER_POINTS);
                LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intentRefreshUI);

                SharedPreferences sharedPreferences = getSharedPreferences(Constants.SHARE_PRE_FILE, Context.MODE_PRIVATE);
                //only if 'remember me' is active, then write to local DB
                if (sharedPreferences.getLong(Constants.PERSISTENT_SESSION, -1) >= 0) {

                    SQLiteDatabase db = databaseHelper.getWritableDatabase();

                    // Create a map of values, where column names are the keys
                    ContentValues values = new ContentValues();
                    values.put(EcoQuestDBContract.UserTable.POINTS, User.getInstance().getPoints());

                    // update total points for user
                    String selection = EcoQuestDBContract.UserTable._ID + " = ?";
                    String[] selectionArgs = {Long.toString(User.getInstance().getUserID())};

                    db.update(
                            EcoQuestDBContract.UserTable.TABLE_NAME,
                            values,
                            selection,
                            selectionArgs);

                    //insert completed quest for the user in local DB
                    ContentValues valuesQuestId = new ContentValues();
                    valuesQuestId.put(EcoQuestDBContract.CompletedQuest.USER_ID, Long.toString(User.getInstance().getUserID()));
                    valuesQuestId.put(EcoQuestDBContract.CompletedQuest.QUEST_ID, ecoQuestID);

                    db.insert(EcoQuestDBContract.CompletedQuest.TABLE_NAME, null, valuesQuestId);

                    databaseHelper.close();
                }

                // insert ecoQuestID in remote DB table
                // update points on remote DB
                try {
                    updateRemoteUserPoints(User.getInstance().getEmail(), String.valueOf(User.getInstance().getPoints()));
                    updateEcoQuestsRemoteDB(User.getInstance().getUserID(), ecoQuestID);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }
    }

    private void updateRemoteUserPoints(String user_email, String points) throws IOException {
        HashMap<String, String> userCredentials = new HashMap<>();

        userCredentials.put("user_login", user_email);
        userCredentials.put("totalpoints", points);

        String urlParameters = getDataString(userCredentials);

        // POST CALL
        byte[] postData;
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
            postData = urlParameters.getBytes(StandardCharsets.UTF_8);
        } else
            postData = urlParameters.getBytes(Charset.forName("UTF-8"));

        int postDataLength = postData.length;

        String request = "http://www.keyscience.org/wp-content/app/userprofile/updateUserPoints.php";

        URL url = new URL(request);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setDoOutput(true);
        conn.setDoInput(true);
        conn.setInstanceFollowRedirects(false);

        conn.setRequestMethod("POST");
        conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
        conn.setRequestProperty("charset", "utf-8");
        conn.setRequestProperty("Content-Length", Integer.toString(postDataLength));
        conn.setUseCaches(false);

        DataOutputStream wr = new DataOutputStream(conn.getOutputStream());
        wr.write(postData);
        wr.close();

        // READ PHP OUTPUT
        String inputLine;
        InputStream in = conn.getInputStream();
        BufferedReader reader = new BufferedReader(new InputStreamReader(in));

        while ((inputLine = reader.readLine()) != null) {
            if (!inputLine.equals("FAIL!")) {
                String readInputLine = inputLine;
            }
        }
        in.close();
    }

    private void updateEcoQuestsRemoteDB(long userID, int ecoquestID) throws IOException {
        HashMap<String, String> parameters = new HashMap<>();

        parameters.put("user_id", Long.toString(userID));
        parameters.put("ecoquest_id", Long.toString(ecoquestID));

        String urlParameters = getDataString(parameters);

        // POST CALL
        byte[] postData;
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
            postData = urlParameters.getBytes(StandardCharsets.UTF_8);
        } else
            postData = urlParameters.getBytes(Charset.forName("UTF-8"));

        int postDataLength = postData.length;

        String request = "http://www.keyscience.org/wp-content/app/EcoQuest/userEcoQuests.php";

        URL url = new URL(request);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setDoOutput(true);
        conn.setDoInput(true);
        conn.setInstanceFollowRedirects(false);

        conn.setRequestMethod("POST");
        conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
        conn.setRequestProperty("charset", "utf-8");
        conn.setRequestProperty("Content-Length", Integer.toString(postDataLength));
        conn.setUseCaches(false);

        DataOutputStream wr = new DataOutputStream(conn.getOutputStream());
        wr.write(postData);
        wr.close();

        // READ PHP OUTPUT
        String inputLine;
        InputStream in = conn.getInputStream();
        BufferedReader reader = new BufferedReader(new InputStreamReader(in));

        while ((inputLine = reader.readLine()) != null) {
            if (!inputLine.equals("FAIL!")) {
            }
        }
        in.close();
    }

    private static String getDataString(HashMap<String, String> params) throws UnsupportedEncodingException {
        StringBuilder result = new StringBuilder();
        boolean first = true;
        for (Map.Entry<String, String> entry : params.entrySet()) {
            if (first)
                first = false;
            else
                result.append("&");
            result.append(URLEncoder.encode(entry.getKey(), "UTF-8"));
            result.append("=");
            result.append(URLEncoder.encode(entry.getValue(), "UTF-8"));
        }
        return result.toString();
    }

    public static Bitmap drawableToBitmap(Drawable drawable) {
        Bitmap bitmap = null;

        if (drawable instanceof BitmapDrawable) {
            BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
            if (bitmapDrawable.getBitmap() != null) {
                return bitmapDrawable.getBitmap();
            }
        }

        if (drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) {
            bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); // Single color bitmap will be created of 1x1 pixel
        } else {
            bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
        }

        Canvas canvas = new Canvas(bitmap);
        drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
        drawable.draw(canvas);
        return bitmap;
    }

    private void sendNotification(String geoFenceID) {
        SingletonEcoQuests singletonEcoQuests = SingletonEcoQuests.getInstance();
        EcoQuestModel ecoQuestModel = singletonEcoQuests.getHashMap().get(Integer.parseInt(geoFenceID));

        if (ecoQuestModel != null) {

            Intent notifyIntent = new Intent(this, EcoQuestInfoActivity.class);
            notifyIntent.putExtra("TITLE", ecoQuestModel.getEducationTitle());
            notifyIntent.putExtra("CONTENT", ecoQuestModel.getEducationDescription());
            notifyIntent.putExtra("IMAGE", ecoQuestModel.getEducationImageURL());
            notifyIntent.putExtra("MORE", ecoQuestModel.getEducationLearnMoreURL());

            notifyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
            PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT);

            NotificationCompat.Builder builder;
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
                builder = new NotificationCompat.Builder(this, CHANNEL_ID)
                        .setSmallIcon(R.drawable.ic_radar)
                        .setLargeIcon(drawableToBitmap(getDrawable(R.drawable.ic_radar)))
                        .setContentTitle(ecoQuestModel.getName())
                        .setContentText(ecoQuestModel.getEducationTitle())
                        .setPriority(NotificationCompat.PRIORITY_DEFAULT)
                        .setContentIntent(pendingIntent)  // set pending intent if some action is desired when tapping notification
                        .setAutoCancel(true);
            } else {
                builder = new NotificationCompat.Builder(this, CHANNEL_ID)
                        .setSmallIcon(R.drawable.ic_radar)
                        .setLargeIcon(drawableToBitmap(ContextCompat.getDrawable(getApplicationContext(), R.drawable.ic_radar)))
                        .setContentTitle(ecoQuestModel.getName())
                        .setContentText(ecoQuestModel.getEducationTitle())
                        .setPriority(NotificationCompat.PRIORITY_DEFAULT)
                        .setContentIntent(pendingIntent)  // set pending intent if some action is desired when tapping notification
                        .setAutoCancel(true);
            }

            NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);

// notificationId is a unique int for each notification that you must define
            int notificationId = 1;
            notificationManager.notify(notificationId, builder.build());
        }
    }

    // this is for debugging
    private String getGeofenceTransitionDetails(GeofenceTransitionsIntentService geofenceTransitionsIntentService, int geofenceTransition, List<Geofence> triggeringGeofences) {
        ArrayList<String> triggerfenceList = new ArrayList<>();

        for (Geofence geofence : triggeringGeofences) {
            triggerfenceList.add(geofence.getRequestId());
        }


        String status = null;

        if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER) {
            status = "Entering";
        } else if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT) {
            status = "Exiting";
        }
        return status + TextUtils.join(", ", triggerfenceList);
    }

    // create notification channel
    private void createNotificationChannel() {
        // Create the NotificationChannel, but only on API 26+ because
        // the NotificationChannel class is new and not in the support library
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            int importance = NotificationManager.IMPORTANCE_HIGH;
            NotificationChannel channel = new NotificationChannel(CHANNEL_ID, (CHANNEL_NAME), importance);
            channel.setDescription((CHANNEL_DESCRIPTION));
            // Register the channel with the system; you can't change the importance
            // or other notification behaviors after this
            NotificationManager notificationManager = getSystemService(NotificationManager.class);
            notificationManager.createNotificationChannel(channel);
        }
    }

}
