package org.deke.risk.riskahead;

import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import androidx.viewpager.widget.ViewPager;
import android.util.Log;
import android.widget.ImageView;
import android.widget.LinearLayout;

import com.android.vending.billing.IInAppBillingService;
import com.android.volley.Request;
import com.android.volley.toolbox.StringRequest;
import com.google.firebase.crashlytics.FirebaseCrashlytics;

import org.deke.risk.riskahead.adapter.SubscriptionsPagerAdapter;
import org.deke.risk.riskahead.fragment.SubscriptionItemFragment;
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.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
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 SubscriptionsActivity extends BaseActivity{
    private final static String TAG = SubscriptionsActivity.class.getSimpleName();

    IInAppBillingService mService;
    ServiceConnection mServiceConn;

    private Bundle querySkus;
    private HashMap<String,JSONObject> purchaseMap = new HashMap<>();
    private ArrayList<String> skuList = new ArrayList<>();

    private HashMap<String,String> dbItems = new HashMap<>();
    private ArrayList<String> ownedSkus = new ArrayList<>();

    Handler billingHandler;

    private SubscriptionsPagerAdapter subscriptionsAdapter;
    private ViewPager subscriptionsViewPager;

    private List<ImageView> dots;

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

        skuList.add("no_ads_03");
        skuList.add("extra_functions_03");

        initViewPager();
        addDots();
    }


    private void initViewPager() {
        subscriptionsViewPager = findViewById(R.id.subs_viewpager);
        subscriptionsAdapter = new SubscriptionsPagerAdapter(getSupportFragmentManager(), 2);
        subscriptionsViewPager.setAdapter(subscriptionsAdapter);
    }

    public void addDots() {
        dots = new ArrayList<>();
        LinearLayout dotsLayout = findViewById(R.id.dots);

        for(int i = 0; i < subscriptionsAdapter.getCount(); i++) {
            ImageView dot = new ImageView(this);
            dot.setImageDrawable(getResources().getDrawable(R.drawable.bottom_dot_unselected));

            LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
                    LinearLayout.LayoutParams.WRAP_CONTENT,
                    LinearLayout.LayoutParams.WRAP_CONTENT
            );

            params.setMargins(2,2,2,2);
            dotsLayout.addView(dot, params);

            dots.add(dot);
        }

        subscriptionsViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
            }

            @Override
            public void onPageSelected(int position) {
                selectDot(position);
            }

            @Override
            public void onPageScrollStateChanged(int state) {
            }
        });

        selectDot(0);
    }

    public void selectDot(int idx) {
        Resources res = getResources();
        for(int i = 0; i < subscriptionsAdapter.getCount(); i++) {
            int drawableId = (i==idx)?(R.drawable.bottom_dot_selected):(R.drawable.bottom_dot_unselected);
            Drawable drawable = res.getDrawable(drawableId);
            dots.get(i).setImageDrawable(drawable);
        }
    }

    private void initBillingService() {
        billingHandler = new Handler();

            Thread thread = new Thread() {
                @Override
                public void run() {

                    ServiceConnection mServiceConn = new ServiceConnection() {
                        @Override
                        public void onServiceDisconnected(ComponentName name) {
                            mService = null;
                            Log.d(TAG, "Disconnected from InApp Billing Service");
                        }

                        @Override
                        public void onServiceConnected(ComponentName name,
                                                       IBinder service) {
                            mService = IInAppBillingService.Stub.asInterface(service);
                            Log.d(TAG, "Connected to InApp Billing Service");

                            initBillingOptions();
                            getAlreadyPurchasedItems();
                        }
                    };

                    Intent serviceIntent = new Intent("com.android.vending.billing.InAppBillingService.BIND");
                    serviceIntent.setPackage("com.android.vending");
                    bindService(serviceIntent, mServiceConn, Context.BIND_AUTO_CREATE);

                    querySkus = new Bundle();
                    querySkus.putStringArrayList("ITEM_ID_LIST", skuList);

                }
            };

            thread.start();

    }

    private void getAlreadyPurchasedItems() {
        try {
            Bundle activeSubs = mService.getPurchases(3, getPackageName(),"subs", null);

            int response = activeSubs.getInt("RESPONSE_CODE");
            if (response == 0) {
                ownedSkus = activeSubs.getStringArrayList("INAPP_PURCHASE_ITEM_LIST");
                ArrayList<String>  purchaseDataList = activeSubs.getStringArrayList("INAPP_PURCHASE_DATA_LIST");
                ArrayList<String>  signatureList = activeSubs.getStringArrayList("INAPP_DATA_SIGNATURE_LIST");

                if (purchaseDataList != null && signatureList != null) {
                    for (int i = 0; i < purchaseDataList.size(); ++i) {
                        String purchaseData = purchaseDataList.get(i);
                        String signature = signatureList.get(i);
                        String sku = ownedSkus.get(i);

                        Log.d(TAG, "Already purchased: " + sku + " : " + purchaseData + " : " + signature);
                    }
                }

                getSubscriptionsAndSync(user.get(SessionManager.KEY_UID));

            }
        } catch (RemoteException e) {
            FirebaseCrashlytics crashlytics = FirebaseCrashlytics.getInstance();
            crashlytics.log("RemoteException caught: " + e);
        }
    }

    private void syncWithDatabase(ArrayList<String> ownedSkus) {
        Log.d(TAG, "Sync subs with database...");

        if(dbItems != null){
            Log.d(TAG, "Database shows following active subs: "+dbItems.toString());
        }else{
            Log.d(TAG, "No active subs in Database");
        }

        for(String sub : skuList){
            boolean itemFound = false;

            if(dbItems != null && dbItems.containsKey(sub)){
                for(String sku : ownedSkus){
                    itemFound = itemFound || sku.equals(sub);
                }

                if(!itemFound){
                    Log.d(TAG, "found sub in database which is active but sub already expired: "+sub);
                    deactivateSubscriptionInDB(dbItems.get(sub));
                }
            }
        }

        for(String sku : ownedSkus){
            if(!(dbItems != null && dbItems.containsKey(sku))){
                Log.d(TAG, "Subscription "+sku+" not found in DB, add subscription!");
                addSubscription(sku, "subs", "0", "0");
            }
        }
    }

    private void initBillingOptions() {
        try {
            Bundle skuDetails = mService.getSkuDetails(3, getPackageName(), "subs", querySkus);
            int response = skuDetails.getInt("RESPONSE_CODE");

            Log.d(TAG, "InApp Response_Code: " + response);

            if (response == 0) {
                ArrayList<String> responseList= skuDetails.getStringArrayList("DETAILS_LIST");

                if(responseList != null){
                    for (String thisResponse : responseList) {
                        JSONObject object = new JSONObject(thisResponse);

                        final String sku = object.getString("productId");
                        final String price = object.getString("price");
                        final String title = object.getString("title");
                        final String description = object.getString("description");

                        purchaseMap.put(sku, object);

                        Log.d(TAG,"Product: "+sku+" Price: "+price+" Title: "+title+" Description: "+description);
                    }
                }else{
                    FirebaseCrashlytics.getInstance().log("Could not get responseList");
                }

                ((SubscriptionItemFragment) subscriptionsAdapter.getItem(0)).initSubscription(purchaseMap.get("no_ads_03"));
                ((SubscriptionItemFragment) subscriptionsAdapter.getItem(1)).initSubscription(purchaseMap.get("extra_functions_03"));
            }

        } catch (Exception e) {
            FirebaseCrashlytics.getInstance().log("Exception caught: " + e);
        }
    }


    public void buyProduct(String sku) {
        try {
            Bundle buyIntentBundle = mService.getBuyIntent(3, getPackageName(), sku, "subs", user.get(SessionManager.KEY_UID));

            PendingIntent pendingIntent = buyIntentBundle.getParcelable("BUY_INTENT");

            if (pendingIntent != null) {
                startIntentSenderForResult(pendingIntent.getIntentSender(),1001, new Intent(), 0, 0, 0);
            }
        } catch (Exception e) {
            FirebaseCrashlytics.getInstance().log("Exception caught: " + e);
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == 1001) {
            int responseCode = data.getIntExtra("RESPONSE_CODE", 0);
            String purchaseData = data.getStringExtra("INAPP_PURCHASE_DATA");
            String dataSignature = data.getStringExtra("INAPP_DATA_SIGNATURE");

            Log.d(TAG, "Response Code: " + responseCode + " DataSignature: " + dataSignature);

            if (resultCode == RESULT_OK) {
                try {
                    JSONObject jo = new JSONObject(purchaseData);
                    String sku = jo.getString("productId");

                    showMessage(String.format("%s %s. %s", getResources().getString(R.string.txt_subs_youbought), purchaseMap.get(sku).getString("title"), getResources().getString(R.string.txt_subs_thankyou)));
                    addSubscription(purchaseMap.get(sku).getString("productId"), purchaseMap.get(sku).getString("type"), purchaseMap.get(sku).getString("price_amount_micros"), purchaseMap.get(sku).getString("price_currency_code"));
                } catch (JSONException e) {
                    showMessage(getResources().getString(R.string.txt_errormsg_subs));
                    FirebaseCrashlytics.getInstance().log("JSONException caught while purchasing!: " + e);
                }
            }
        }
    }

    private void addSubscription(String productId, String type, String price, String currency) {
        showDialog();
        String tag_string_req = "requestaddsubscription";
        StringRequest strReq = getStringAddSubscription(productId, type, price, currency);
        AppController.getInstance().addToRequestQueue(strReq, tag_string_req);
    }

    private StringRequest getStringAddSubscription(final String productId, final String type, final String price, final String currency) {
        return new StringRequest(Request.Method.POST, AppConfig.REST_ADD_SUBSCRIPTIONS, response -> {

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

                if (error) {
                    String errorMsg = jObj.getString("error_msg");
                    FirebaseCrashlytics.getInstance().log("Error adding subscription (Server returned error): " + errorMsg);
                    showMessage(getResources().getString(R.string.txt_errormsg_subs));
                } else {
                    gotoSubscriptionsActivity();
                }

            } catch (JSONException e) {
                FirebaseCrashlytics.getInstance().log("JSONException caught: " + e);
            }

            hideDialog();
        }, error -> {
            FirebaseCrashlytics.getInstance().log("Error adding subscription: " + error.getMessage());
            showMessage(getResources().getString(R.string.txt_errormsg_subs));
            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("productid", productId);
                params.put("type", type);
                params.put("pricemicros", price);
                params.put("currencycode", currency);

                return params;
            }
        };
    }

    private void getSubscriptionsAndSync(String userId) {
        String tag_string_req = "requestgetsubscription";
        StringRequest strReq = getStringGetSubscriptions(userId);
        AppController.getInstance().addToRequestQueue(strReq, tag_string_req);
    }

    private StringRequest getStringGetSubscriptions(final String userId) {
        return new StringRequest(Request.Method.POST, AppConfig.REST_GET_SUBSCRIPTIONS, response -> {

            try {
                JSONObject jObj = new JSONObject(response);
                boolean error = jObj.getBoolean("error");
                dbItems = new HashMap<>();

                if (error) {
                    String errorMsg = jObj.getString("error_msg");
                    Log.d(TAG, "Error getting subscription (Server returned error): " + errorMsg);
                    dbItems = null;

                }else{
                    JSONArray subs = jObj.getJSONArray("msg");
                    Log.d(TAG, "SUB FROM DB RECEIVED");

                    for(int i = 0;i < subs.length();i++){
                        dbItems.put(subs.getJSONObject(i).getString("productId"),subs.getJSONObject(i).getString("id"));
                    }
                }

                syncWithDatabase(ownedSkus);

            } catch (JSONException e) {
                FirebaseCrashlytics.getInstance().log("JSONException caught: " + e);
            }
        }, error -> {
            FirebaseCrashlytics.getInstance().log("Error getting subscription: " + 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("userid", userId);

                return params;
            }
        };
    }

    private void  deactivateSubscriptionInDB(String subscriptionId) {
        Log.d(TAG,"Deactivate sub with uid: "+subscriptionId);

        String tag_string_req = "requestdeactivatesubscription";
        StringRequest strReq = getStringDeactivateSubscriptions(subscriptionId);
        AppController.getInstance().addToRequestQueue(strReq, tag_string_req);
    }

    private StringRequest getStringDeactivateSubscriptions(final String subscriptionId) {
        return new StringRequest(Request.Method.POST, AppConfig.REST_DEACTIVATE_SUBSCRIPTIONS, response -> {

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

                if (error) {
                    String errorMsg = jObj.getString("error_msg");
                    FirebaseCrashlytics.getInstance().log("Error deactivating subscription (Server returned error): " + errorMsg);
                }else{
                    Log.d(TAG,"Sub with uid: "+subscriptionId+" deactivated in DB");
                }

            } catch (JSONException e) {
                FirebaseCrashlytics.getInstance().log("JSONException caught: " + e);
            }
        }, error -> FirebaseCrashlytics.getInstance().log("Error deactivating subscription: " + error.getMessage())) {

            @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("subid", subscriptionId);

                return params;
            }
        };
    }

    @Override
    protected void onResume() {
        super.onResume();
        navDrawer.setSelection(subscriptionsAvtivityID, false);
        initBillingService();
    }

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

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

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (mService != null && mServiceConn != null) {
            unbindService(mServiceConn);
        }
    }
}
