package com.steevsapps.idledaddy.billing;

import android.app.Activity;
import androidx.annotation.Nullable;
import android.util.Log;

import com.android.billingclient.api.BillingClient;
import com.android.billingclient.api.BillingClientStateListener;
import com.android.billingclient.api.BillingFlowParams;
import com.android.billingclient.api.Purchase;
import com.android.billingclient.api.PurchasesUpdatedListener;

import java.util.List;

public class BillingManager implements PurchasesUpdatedListener {
    private final static String TAG = BillingManager.class.getSimpleName();

    private Activity activity;
    private BillingUpdatesListener listener;
    private BillingClient billingClient;

    private boolean serviceConnected = false;
    private boolean displayAds = true;

    public BillingManager(Activity activity) {
        this.activity = activity;
        try {
            listener = (BillingUpdatesListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString() + " must implement BillingUpdatesListener.");
        }

        // Setup the billing client
        billingClient = BillingClient.newBuilder(activity).setListener(this).build();

        // Start the setup asynchronously.
        // The specified listener is called once setup completes.
        // New purchases are reported through the onPurchasesUpdated() callback
        // of the class specified using the setListener() method above.
        startServiceConnection(new Runnable() {
            @Override
            public void run() {
                // Query existing purchases
                queryPurchases();
                // Notify the listener that the billing client is ready.
                listener.onBillingClientSetupFinished();
            }
        });
    }

    private void startServiceConnection(final Runnable executeOnSuccess) {
        billingClient.startConnection(new BillingClientStateListener() {
            @Override
            public void onBillingSetupFinished(int responseCode) {
                Log.i(TAG, "Billing setup finished. Response code: " + responseCode);

                if (responseCode == BillingClient.BillingResponse.OK) {
                    serviceConnected = true;
                    if (executeOnSuccess != null) {
                        executeOnSuccess.run();
                    }
                }
            }

            @Override
            public void onBillingServiceDisconnected() {
                Log.i(TAG, "Billing service disconnected");
                serviceConnected = false;
            }
        });
    }

    private void executeServiceRequest(Runnable runnable) {
        if (serviceConnected) {
            runnable.run();
        } else {
            // If billing service was disconnected, we try to reconnect 1 time.
            startServiceConnection(runnable);
        }
    }

    private void queryPurchases() {
        final Purchase.PurchasesResult result = billingClient.queryPurchases(BillingClient.SkuType.INAPP);
        final List<Purchase> purchases = result.getPurchasesList();
        if (purchases != null) {
            for (Purchase purchase : purchases) {
                handlePurchase(purchase);
            }
        }
    }

    @Override
    public void onPurchasesUpdated(int responseCode, @Nullable List<Purchase> purchases) {
        if (responseCode == BillingClient.BillingResponse.OK && purchases != null) {
            for (Purchase purchase : purchases) {
                handlePurchase(purchase);
            }
            Log.i(TAG, "Purchases updated.");
            listener.onPurchasesUpdated(purchases);
        } else if (responseCode == BillingClient.BillingResponse.USER_CANCELED) {
            // Handle an error caused by a user canceling the purchase flow.
            Log.i(TAG, "Purchase canceled.");
            listener.onPurchaseCanceled();
        } else {
            // Handle any other error codes.
            Log.i(TAG, "Unknown error. Response code: " + responseCode);
        }
    }

    private void handlePurchase(Purchase purchase) {
        if ("remove_ads".equals(purchase.getSku())) {
            displayAds = false;
        }
    }

    public boolean shouldDisplayAds() {
        return displayAds;
    }

    public void destroy() {
        if (billingClient != null && billingClient.isReady()) {
            billingClient.endConnection();
            billingClient = null;
        }
    }

    public void launchPurchaseFlow() {
        final Runnable runnable = new Runnable() {
            @Override
            public void run() {
                final BillingFlowParams params = BillingFlowParams.newBuilder()
                        .setSku("remove_ads")
                        .setType(BillingClient.SkuType.INAPP)
                        .build();
                billingClient.launchBillingFlow(activity, params);
            }
        };
        executeServiceRequest(runnable);
    }
}