package com.bazaar;

import com.bazaar.util.IabHelper;
import com.bazaar.util.IabHelper.OnConsumeFinishedListener;
import com.bazaar.util.IabHelper.OnConsumeMultiFinishedListener;
import com.bazaar.util.IabHelper.OnIabPurchaseFinishedListener;
import com.bazaar.util.IabHelper.OnIabSetupFinishedListener;
import com.bazaar.util.IabHelper.QueryInventoryFinishedListener;
import com.bazaar.util.IabHelper.QuerySkuDetailsFinishedListener;
import com.bazaar.util.IabHelper.QueryPurchasesFinishedListener;
import com.bazaar.util.IabResult;
import com.bazaar.util.Inventory;
import com.bazaar.util.Purchase;
import com.bazaar.util.SkuDetails;

import android.app.Activity;
import android.content.Intent;
import android.util.Log;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.json.JSONException;
import org.json.JSONObject;

public class BazaarIABPlugin extends BazaarIABPluginBase
	implements 
	  IabHelper.QueryInventoryFinishedListener
	, IabHelper.QuerySkuDetailsFinishedListener
	, IabHelper.QueryPurchasesFinishedListener
	, IabHelper.OnIabPurchaseFinishedListener
	, IabHelper.OnConsumeFinishedListener
	, IabHelper.OnConsumeMultiFinishedListener
{
	private static String BILLING_NOT_RUNNING_ERROR = "The billing service is not running or billing is not supported. Aborting.";
	private static BazaarIABPlugin mInstance;
	
	private IabHelper mHelper;
	private List<Purchase> mPurchases = new ArrayList();
	private List<SkuDetails> mSkus;
	
	public static BazaarIABPlugin instance()
	{
		if (mInstance == null)
			mInstance = new BazaarIABPlugin();
		
		return mInstance;
	}
	
	public IabHelper getIabHelper()
	{
		return mHelper;
	}
	
	public void enableLogging(boolean shouldEnable)
	{
		IABLogger.DEBUG = shouldEnable;
		if (mHelper != null)
			mHelper.enableDebugLogging(true);
	}
	
	public void init(String publicKey)
	{
		IABLogger.logEntering(getClass().getSimpleName(), "init", publicKey);
		
		mPurchases = new ArrayList();
		mHelper = new IabHelper(getActivity(), publicKey);
		mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener()
		{
			public void onIabSetupFinished(IabResult result)
			{
				if (result.isSuccess())
				{
					UnitySendMessage("billingSupported", "");
				}
				else
				{
					Log.i(TAG, "billing not supported: " + result.getMessage());
					UnitySendMessage("billingNotSupported", result.getMessage());
					mHelper = null;
				}
			}
		});
	}
	
	public void unbindService()
	{
		IABLogger.logEntering(getClass().getSimpleName(), "unbindService");
		if (mHelper != null)
		{
			mHelper.dispose();
			mHelper = null;
		}
	}
	
	public boolean areSubscriptionsSupported()
	{
		IABLogger.logEntering(getClass().getSimpleName(), "areSubscriptionsSupported");
		if (mHelper == null) {
			return false;
		}
		return mHelper.subscriptionsSupported();
	}
	
	public void queryInventory(final String[] skus)
	{
		IABLogger.logEntering(getClass().getSimpleName(), "queryInventory", skus);
		if (mHelper == null)
		{
			Log.i(TAG, BILLING_NOT_RUNNING_ERROR);
			return;
		}
		runSafelyOnUiThread(new Runnable()
		{
			public void run()
			{
				mHelper.queryInventoryAsync(true, Arrays.asList(skus), BazaarIABPlugin.this);
			}
		}, "queryInventoryFailed");
	}
	
	public void onQueryInventoryFinished(IabResult result, Inventory inventory)
	{
		if (result.isSuccess())
		{
			mPurchases = inventory.getAllPurchases();
			mSkus = inventory.getAllSkuDetails();
			
			UnitySendMessage("queryInventorySucceeded", inventory.getAllSkusAndPurchasesAsJson());
		}
		else
		{
			UnitySendMessage("queryInventoryFailed", result.getMessage());
		}
	}
	
	public void querySkuDetails(final String[] skus)
	{
		IABLogger.logEntering(getClass().getSimpleName(), "querySkuDetails", skus);
		if (mHelper == null)
		{
			Log.i(TAG, BILLING_NOT_RUNNING_ERROR);
			return;
		}
		runSafelyOnUiThread(new Runnable()
		{
			public void run()
			{
				mHelper.querySkuDetailsAsync(Arrays.asList(skus), BazaarIABPlugin.this);
			}
		}, "querySkuDetailsFailed");
	}
	
	public void onQuerySkuDetailsFinished(IabResult result, Inventory inventory)
	{
		if (result.isSuccess())
		{
			mSkus = inventory.getAllSkuDetails();
			String skusStr = inventory.getAllSkusAsJson().toString();
			
			UnitySendMessage("querySkuDetailsSucceeded", skusStr);
		}
		else
		{
			UnitySendMessage("querySkuDetailsFailed", result.getMessage());
		}
	}
	
	public void queryPurchases()
	{
		IABLogger.logEntering(getClass().getSimpleName(), "queryPurchases");
		if (mHelper == null)
		{
			Log.i(TAG, BILLING_NOT_RUNNING_ERROR);
			return;
		}
		runSafelyOnUiThread(new Runnable()
		{
			public void run()
			{
				mHelper.queryPurchasesAsync(BazaarIABPlugin.this);
			}
		}, "queryInventoryFailed");
	}
	
	public void onQueryPurchasesFinished(IabResult result, Inventory inventory)
	{
		if (result.isSuccess())
		{
			mPurchases = inventory.getAllPurchases();
			String purchasesStr = inventory.getAllPurchasesAsJson().toString();
		
			UnitySendMessage("queryPurchasesSucceeded", purchasesStr);
		}
		else
		{
			UnitySendMessage("queryPurchasesFailed", result.getMessage());
		}
	}
	
	public void purchaseProduct(final String sku, final String developerPayload)
	{
		IABLogger.logEntering(getClass().getSimpleName(), "purchaseProduct", new Object[] { sku, developerPayload });
		if (mHelper == null)
		{
			Log.i(TAG, BILLING_NOT_RUNNING_ERROR);
			return;
		}
		
		for (Purchase p : mPurchases)
		{
			if (p.getSku().equalsIgnoreCase(sku)) 
			{
				Log.i(TAG, "Attempting to purchase an item that has already been purchased. That is probably not a good idea: " + sku);
			}
		}
		
		final String f_itemType = "inapp";
		runSafelyOnUiThread(new Runnable()
		{
			public void run()
			{
				Intent proxyStarter = new Intent(getActivity(), BazaarIABProxyActivity.class);
				proxyStarter.putExtra("sku", sku);
				proxyStarter.putExtra("itemType", f_itemType);
				proxyStarter.putExtra("developerPayload", developerPayload);
				getActivity().startActivity(proxyStarter);
			}
		}, "purchaseFailed");
	}
	
	public void onIabPurchaseFinished(IabResult result, Purchase info)
	{
		if (result.isSuccess())
		{
			if (!mPurchases.contains(info)) {
				mPurchases.add(info);
			}
			UnitySendMessage("purchaseSucceeded", info.toJson());
		}
		else
		{
			UnitySendMessage("purchaseFailed", result.getMessage());
		}
	}
	
	public void consumeProduct(String sku)
	{
		IABLogger.logEntering(getClass().getSimpleName(), "consumeProduct", sku);
		if (mHelper == null)
		{
			Log.i(TAG, BILLING_NOT_RUNNING_ERROR);
			return;
		}
			
		final Purchase purchase = getPurchasedProductForSku(sku);
		if (purchase == null)
		{
			Log.i(TAG, "Attempting to consume an item that has not been purchased. Aborting to avoid exception. sku: " + sku);
			UnitySendMessage("consumePurchaseFailed", sku + ": you cannot consume a project that has not been purchased or if you have not first queried your inventory to retreive the purchases.");
			return;
		}
		
		runSafelyOnUiThread(new Runnable()
		{
			public void run()
			{
				mHelper.consumeAsync(purchase, BazaarIABPlugin.this);
			}
		}, "consumePurchaseFailed");
	}
	
	private Purchase getPurchasedProductForSku(String sku)
	{
		for (Purchase p : mPurchases) 
		{
			if (p.getSku().equalsIgnoreCase(sku)) 
			{
				return p;
			}
		}
		return null;
	}
	
	public void onConsumeFinished(Purchase purchase, IabResult result)
	{
		if (result.isSuccess())
		{
			if (mPurchases.contains(purchase)) 
			{
				mPurchases.remove(purchase);
			}
			
			UnitySendMessage("consumePurchaseSucceeded", purchase.toJson());
		}
		else
		{
			String res = purchase.getSku() + ": " + result.getMessage();
			UnitySendMessage("consumePurchaseFailed", res);
		}
	}
	
	public void consumeProducts(String[] skus)
	{
		IABLogger.logEntering(getClass().getSimpleName(), "consumeProducts", skus);
		if (mHelper == null)
		{
			Log.i(TAG, BILLING_NOT_RUNNING_ERROR);
			return;
		}
		
		if ((mPurchases == null) || (mPurchases.size() == 0))
		{
			Log.e(TAG, "there are no purchases available to consume");
			return;
		}
		
		final List<Purchase> confirmedPurchases = new ArrayList();
		for (String sku : skus)
		{
			Purchase purchase = getPurchasedProductForSku(sku);
			if (purchase != null) 
			{
				confirmedPurchases.add(purchase);
			}
		}
		
		if (confirmedPurchases.size() != skus.length)
		{
			Log.i(TAG, "Attempting to consume " + skus.length + " item(s) but only " + confirmedPurchases.size() + " item(s) were found to be purchased. Aborting.");
			return;
		}
		
		runSafelyOnUiThread(new Runnable()
		{
			public void run()
			{
				mHelper.consumeAsync(confirmedPurchases, BazaarIABPlugin.this);
			}
		}, "consumePurchaseFailed");
	}
	
	public void onConsumeMultiFinished(List<Purchase> purchases, List<IabResult> results)
	{
		for (int i = 0; i < results.size(); ++i)
		{
			IabResult result = (IabResult)results.get(i);
			Purchase purchase = (Purchase)purchases.get(i);
			if (result.isSuccess())
			{
				if (mPurchases.contains(purchase)) 
				{
					mPurchases.remove(purchase);
				}
				
				UnitySendMessage("consumePurchaseSucceeded", purchase.toJson());
			}
			else
			{
				String res = purchase.getSku() + ": " + result.getMessage();
				UnitySendMessage("consumePurchaseFailed", res);
			}
		}
	}
	
}