package org.onepf.oms;

import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.RemoteException;
import android.telephony.TelephonyManager;
import android.util.Log;

import com.aptoide.amethyst.Aptoide;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.octo.android.robospice.SpiceManager;
import com.octo.android.robospice.persistence.DurationInMillis;
import com.octo.android.robospice.persistence.exception.SpiceException;
import com.octo.android.robospice.request.listener.RequestListener;

import java.io.IOException;
import java.util.ArrayList;
import java.util.concurrent.CountDownLatch;

import com.aptoide.amethyst.openiab.IABPurchaseActivity;
import com.aptoide.amethyst.openiab.webservices.IabConsumeRequest;
import com.aptoide.amethyst.openiab.webservices.IabPurchasesRequest;
import com.aptoide.amethyst.openiab.webservices.IabSkuDetailsRequest;
import com.aptoide.amethyst.openiab.webservices.json.IabConsumeJson;
import com.aptoide.amethyst.openiab.webservices.json.IabPurchasesJson;
import com.aptoide.amethyst.openiab.webservices.json.IabSkuDetailsJson;

/**
 * Created by j-pac on 12-02-2014.
 */
public class BillingBinder extends IOpenInAppBillingService.Stub {

    // Response result codes
    public static final int RESULT_OK = 0;
    public static final int RESULT_USER_CANCELED = 1;
    public static final int RESULT_BILLING_UNAVAILABLE = 3;
    public static final int RESULT_ITEM_UNAVAILABLE = 4;
    public static final int RESULT_DEVELOPER_ERROR = 5;
    public static final int RESULT_ERROR = 6;
    public static final int RESULT_ITEM_ALREADY_OWNED = 7;
    public static final int RESULT_ITEM_NOT_OWNED = 8;

    // Keys for the responses
    public static final String RESPONSE_CODE = "RESPONSE_CODE";
    public static final String DETAILS_LIST = "DETAILS_LIST";
    public static final String BUY_INTENT = "BUY_INTENT";


    public static final String INAPP_PURCHASE_DATA = "INAPP_PURCHASE_DATA";
    public static final String INAPP_DATA_SIGNATURE = "INAPP_DATA_SIGNATURE";
    public static final String INAPP_PURCHASE_ITEM_LIST = "INAPP_PURCHASE_ITEM_LIST";
    public static final String INAPP_PURCHASE_DATA_LIST = "INAPP_PURCHASE_DATA_LIST";
    public static final String INAPP_DATA_SIGNATURE_LIST = "INAPP_DATA_SIGNATURE_LIST";
    public static final String INAPP_CONTINUATION_TOKEN = "INAPP_CONTINUATION_TOKEN";

    // Param keys
    public static final String ITEM_ID_LIST = "ITEM_ID_LIST";
    public static final String ITEM_TYPE_LIST = "ITEM_TYPE_LIST";

    // Item types
    public static final String ITEM_TYPE_INAPP = "inapp";
    public static final String ITEM_TYPE_SUBS = "subs";
    public static final String SERVICES_LIST = "SERVICES_LIST";
    private final SpiceManager manager;


    private Context context;

    public BillingBinder(Context context, SpiceManager manager) {
        this.context = context;
        this.manager = manager;
    }

    @Override
    public int isBillingSupported(int apiVersion, String packageName, String type) throws RemoteException {
        Log.d("AptoideBillingService", "[isBillingSupported]: " + packageName);


        if (apiVersion >= 3 &&
                (type.equals(BillingBinder.ITEM_TYPE_INAPP) || type.equals(BillingBinder.ITEM_TYPE_SUBS))) {
            return RESULT_OK;
        } else {
            return RESULT_BILLING_UNAVAILABLE;
        }
    }

    private String getMccCode(String networkOperator) {
        return networkOperator == null ? "" : networkOperator.substring(0, mncPortionLength(networkOperator));

    }

    private String getMncCode(String networkOperator) {
        return networkOperator == null ? "" : networkOperator.substring(mncPortionLength(networkOperator));

    }

    private int mncPortionLength(String networkOperator) {
        return Math.min(3, networkOperator.length());
    }

    @Override
    public Bundle getSkuDetails(int apiVersion, String packageName, String type, Bundle skusBundle) throws RemoteException {
        Log.d("AptoideBillingService", "[getSkuDetails]: " + packageName + " " + type);

        final Bundle result = new Bundle();

        if (!skusBundle.containsKey(ITEM_ID_LIST) || apiVersion < 3) {
            result.putInt(RESPONSE_CODE, RESULT_DEVELOPER_ERROR);
            return result;
        }

        ArrayList<String> itemIdList = skusBundle.getStringArrayList(ITEM_ID_LIST);

        if ( itemIdList == null || itemIdList.size() <= 0 ) {
            result.putInt(RESPONSE_CODE, RESULT_DEVELOPER_ERROR);
            return result;
        }

        try {
            AccountManager accountManager = AccountManager.get(context);
            String token = accountManager.blockingGetAuthToken(accountManager.getAccountsByType(Aptoide.getConfiguration().getAccountType())[0], "Full access", true);
            //String token =  "27286b943179065fcef3b6adcafe8680d8515e4652010602c45f6";
            TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);

            if(token != null) {
                IabSkuDetailsRequest request = new IabSkuDetailsRequest();
                request.setApiVersion(Integer.toString(apiVersion));
                request.setPackageName(packageName);
                request.setToken(token);

                if(telephonyManager != null && telephonyManager.getSimState()==TelephonyManager.SIM_STATE_READY){
                    request.setMcc(getMccCode(telephonyManager.getNetworkOperator()));
                    request.setMnc(getMncCode(telephonyManager.getNetworkOperator()));
                    request.setSimcc(telephonyManager.getSimCountryIso());
                }


                //request.setOemid(((AptoideConfigurationPartners)Aptoide.getConfiguration()).PARTNERID);
                for(String itemId : itemIdList) {
                    request.addToSkuList(itemId);
                    Log.d("AptoideBillingService", "Sku details request for " + itemId);
                }

                final CountDownLatch latch = new CountDownLatch(1);
                manager.execute(request, packageName + "-getSkuDetails-" + request.getSkuList() + token, DurationInMillis.ONE_SECOND*5, new RequestListener<IabSkuDetailsJson>() {
                    @Override
                    public void onRequestFailure(SpiceException spiceException) {

                        result.putInt(RESPONSE_CODE, RESULT_ERROR);
                        latch.countDown();

                    }

                    @Override
                    public void onRequestSuccess(IabSkuDetailsJson response) {
                        ArrayList<String> detailsList = new ArrayList<String>();

                        if("OK".equals(response.getStatus())) {

                            for(IabSkuDetailsJson.PurchaseDataObject details : response.getPublisher_response().getDetailss_list()) {


                                String s = "";
                                try {
                                    s = new ObjectMapper().writeValueAsString(details);
                                } catch (JsonProcessingException e) {
                                    e.printStackTrace();
                                }

                                detailsList.add(s);
                                Log.d("AptoideBillingService", "Sku Details: " + s);

                            }

                            if (detailsList.size() == 0) {
                                result.putInt(RESPONSE_CODE, RESULT_ITEM_UNAVAILABLE);
                            } else {
                                result.putInt(RESPONSE_CODE, RESULT_OK);
                                result.putStringArrayList(DETAILS_LIST, detailsList);
                            }
                        } else {
                            Log.d("AptoideBillingService", "Response not ok ");
                            result.putInt(RESPONSE_CODE, RESULT_DEVELOPER_ERROR);
                        }
                        latch.countDown();
                    }
                });

                latch.await();


            }


        } catch (Exception e) {
            e.printStackTrace();
            result.putInt(RESPONSE_CODE, RESULT_ERROR);
        }

        return result;
    }

    @Override
    public Bundle getBuyIntent(int apiVersion, String packageName, String sku, String type, String developerPayload) throws RemoteException {
        Log.d("AptoideBillingService", "[getBuyIntent]: " + packageName + " " + type);

        Bundle result = new Bundle();

        PendingIntent pendingIntent;
        Intent purchaseIntent = new Intent(context, /*Aptoide.getConfiguration().*/getIABPurchaseActivityClass());

        if (apiVersion < 3 || !(type.equals(ITEM_TYPE_INAPP) || type.equals(ITEM_TYPE_SUBS))) {
            result.putInt(RESPONSE_CODE, RESULT_DEVELOPER_ERROR);
        } else {
            AccountManager accountManager = AccountManager.get(context);
            Account[] accounts = accountManager.getAccountsByType(Aptoide.getConfiguration().getAccountType());

            if(accounts.length == 0) {
                Log.d("AptoideBillingService", "BillingUnavailable: user not logged in");
            }else{
                try {

                    String token = accountManager.blockingGetAuthToken(accounts[0], "Full access", true);
                    purchaseIntent.putExtra("token", token);
                    purchaseIntent.putExtra("user", accounts[0].name);

                } catch (OperationCanceledException e) {
                    result.putInt(RESPONSE_CODE, RESULT_ERROR);
                    e.printStackTrace();
                } catch (IOException e) {
                    result.putInt(RESPONSE_CODE, RESULT_ERROR);
                    e.printStackTrace();
                } catch (AuthenticatorException e) {
                    result.putInt(RESPONSE_CODE, RESULT_ERROR);
                    e.printStackTrace();
                }
            }

            purchaseIntent.putExtra("developerPayload", developerPayload);
            purchaseIntent.putExtra("apiVersion", apiVersion);
            purchaseIntent.putExtra("type", type);
            purchaseIntent.putExtra("packageName", packageName);
            purchaseIntent.putExtra("sku", sku);

            result.putInt(RESPONSE_CODE, RESULT_OK);

        }

        pendingIntent = PendingIntent.getActivity(context, 0, purchaseIntent, PendingIntent.FLAG_UPDATE_CURRENT);
        result.putParcelable(BUY_INTENT, pendingIntent);
        return result;
    }

    public Class getIABPurchaseActivityClass(){
        return IABPurchaseActivity.class;
    }

    @Override
    public Bundle getPurchases(int apiVersion, String packageName, String type, String continuationToken) throws RemoteException {
        Log.d("AptoideBillingService", "[getPurchases]: " + packageName + " " + type);

        final Bundle result = new Bundle();

        if (apiVersion < 3 || !(type.equals(ITEM_TYPE_INAPP) || type.equals(ITEM_TYPE_SUBS))) {
            result.putInt(RESPONSE_CODE, RESULT_DEVELOPER_ERROR);
            return result;
        }

        AccountManager accountManager = AccountManager.get(context);
        Account[] accounts = accountManager.getAccountsByType(Aptoide.getConfiguration().getAccountType());

        if(accounts.length == 0) {

            Log.d("AptoideBillingService", "BillingUnavailable: user not logged in");
            result.putStringArrayList(INAPP_PURCHASE_ITEM_LIST, new ArrayList<String>());
            result.putStringArrayList(INAPP_PURCHASE_DATA_LIST, new ArrayList<String>());
            result.putStringArrayList(INAPP_DATA_SIGNATURE_LIST, new ArrayList<String>());
            result.putInt(RESPONSE_CODE, RESULT_OK);

            return result;
        }

        try {
            String token = accountManager.blockingGetAuthToken(accounts[0], "Full access", true);

            if(token != null) {
                final CountDownLatch latch = new CountDownLatch(1);
                IabPurchasesRequest request = new IabPurchasesRequest();
                request.setApiVersion(Integer.toString(apiVersion));
                request.setPackageName(packageName);
                request.setType(type);
                request.setToken(token);

                manager.execute(request, packageName + "-getPurchases-"+type, DurationInMillis.ONE_SECOND*5, new RequestListener<IabPurchasesJson>() {
                    @Override
                    public void onRequestFailure(SpiceException spiceException) {
                        result.putInt(RESPONSE_CODE, RESULT_ERROR);
                        latch.countDown();
                    }

                    @Override
                    public void onRequestSuccess(IabPurchasesJson response) {
                        if("OK".equals(response.getStatus())) {

                            ArrayList<String> purchaseItemList = (ArrayList<String>) response.getPublisher_response().getItemList();
                            ArrayList<String> purchaseSignatureList = (ArrayList<String>) response.getPublisher_response().getSignatureList();

                            ArrayList<String> purchaseDataList = new ArrayList<String>();
                            for(IabPurchasesJson.PublisherResponse.PurchaseDataObject purchase : response.getPublisher_response().getPurchaseDataList()) {
                                Log.d("AptoideBillingService", "Purchase: " + purchase.getJson());
                                purchaseDataList.add(purchase.getJson());
                            }

                            result.putStringArrayList(INAPP_PURCHASE_ITEM_LIST, purchaseItemList);
                            result.putStringArrayList(INAPP_PURCHASE_DATA_LIST, purchaseDataList);
                            result.putStringArrayList(INAPP_DATA_SIGNATURE_LIST, purchaseSignatureList);
                            if(response.getPublisher_response().getInapp_continuation_token() != null) {
                                result.putString(INAPP_CONTINUATION_TOKEN, response.getPublisher_response().getInapp_continuation_token());
                            }
                            result.putInt(RESPONSE_CODE, RESULT_OK);
                        } else {
                            result.putInt(RESPONSE_CODE, RESULT_DEVELOPER_ERROR);
                        }
                        latch.countDown();
                    }
                });

                latch.await();

            }

        } catch (Exception e) {
            e.printStackTrace();
            result.putInt(RESPONSE_CODE, RESULT_ERROR);
        }
        return result;
    }


    @Override
    public int consumePurchase(int apiVersion, String packageName, String purchaseToken) throws RemoteException {
        Log.d("AptoideBillingService", "[consumePurchase]: " + packageName + " " + purchaseToken);

        if(apiVersion < 3) {
            return RESULT_DEVELOPER_ERROR;
        }

        try {
            AccountManager accountManager = AccountManager.get(context);
            String token = accountManager.blockingGetAuthToken(accountManager.getAccountsByType(Aptoide.getConfiguration().getAccountType())[0], "Full access", true);

            final int[] result = {RESULT_OK};
            if(token != null) {
                IabConsumeRequest request = new IabConsumeRequest();
                request.setApiVersion(Integer.toString(apiVersion));
                request.setToken(token);
                request.setPackageName(packageName);
                request.setPurchaseToken(purchaseToken);

                final CountDownLatch latch = new CountDownLatch(1);
                manager.execute(request, new RequestListener<IabConsumeJson>() {
                    @Override
                    public void onRequestFailure(SpiceException spiceException) {
                        latch.countDown();
                    }

                    @Override
                    public void onRequestSuccess(IabConsumeJson response) {
                        if("OK".equals(response.getStatus())) {
                            result[0] =  RESULT_OK;
                        }else{
                            result[0] =  RESULT_ERROR;
                        }
                        latch.countDown();

                    }
                });
                latch.await();
                return result[0];
            }




        } catch (OperationCanceledException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (AuthenticatorException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return RESULT_ITEM_NOT_OWNED;
    }
}