/* 
 * Copyright (c)2009-2025 DemiVision, LLC. All Rights Reserved. The information 
 * herein is the CONFIDENTIAL and PROPRIETARY information of DemiVision, LLC. 
 */

using DXLib.Billing;
using DXLib.Data;
using DXLib.Utils;

namespace iStatVball3;

/*
 * Provides functionality for working with Team-Season purchases including tracking the free trial period.
 */
public static class PurchaseEngine
{
	/* Constants */

	// Free trial period (14 days)
	private static readonly TimeSpan TrialDuration = TimeSpan.FromDays( 14 );

	// Product ID list for store query
	private static readonly string[] ProductIds =
	[
		Purchase.TeamSeasons1Id,
		Purchase.TeamSeasons2Id,
		Purchase.TeamSeasons3Id,
		Purchase.TeamSeasons4Id
	];

	/* Methods */

	// Returns % discount level for specified product
	public static double DiscountForProduct( string productId, List<DXBillingProduct> products )
	{
		int count = Purchase.GetCount( productId );

		// Calc full price for N units
		double basePrice = DXBillingProduct.GetPrice( Purchase.TeamSeasons1Id, products );
		double fullPrice = (basePrice * count);

		// Calc absolute discount
		double price = DXBillingProduct.GetPrice( productId, products );
		double discount = (fullPrice - price);

		// Return discount percentage
		return ((discount / fullPrice) * 100);
	}

	// Queries AppStore for list of available products
	public static async Task<List<DXBillingProduct>> GetProducts()
	{
		return await DXBilling.GetProducts( ProductIds, DXBilling.ProductType.Consumable );
	}

	// Finds Team-Season purchase available to be allocated to season
	public static async Task<string> Allocate( User user )
	{
		bool purchased = HasPurchased( user );

		// Use free trial (unless already purchased)
		if ( !IsTrialUsed( user ) && !purchased )
		{
			await user.UpdateTrial( DateTimeOffset.Now );

			return Purchase.FreeTrialId;
		}

		// Use purchase
		if ( purchased )
		{
			List<Purchase> purchases = user.Purchases.OrderBy( p => p.Created ).ToList();

			// Find first purchase with open slot (oldest first)
			foreach ( Purchase purchase in purchases )
			{
				if ( purchase.Remaining > 0 )
				{
					purchase.Used++;

					// Deduct from remaining
					await user.UpdatePurchase( purchase );

					return purchase.UniqueId;
				}
			}
		}

		return null;
	}

	// Removes an allocated purchase from specified user
	public static async Task Deallocate( User user, Season season )
	{
		// Cannot deallocate once season has been used
		if ( !season.IsConsumed )
		{
			// Find first used purchase
			foreach ( Purchase purchase in user.Purchases )
			{
				if ( purchase.Used > 0 )
				{
					purchase.Used--;

					// Deduct from used
					await user.UpdatePurchase( purchase );
					break;
				}
			}
		}
	}

	// Records purchase for specified user
	public static async Task Record( User user, string productId, string purchaseId, int count )
	{
		// Stored as map within user
		Purchase purchase = new()
		{
			ProductId = productId,
			PurchaseId = purchaseId,
			Platform = DXDevice.PlatformOSKey,

			Count = count,
			Used = 0
		};

		// Persist
		await user.UpdatePurchase( purchase );
	}

	/* Purchases */

	// Determines if specified user has made any purchases
	public static bool HasPurchased( User user )
	{
		return (user.Purchases.Count > 0);
	}

	// Returns total number of purchased Team-Seasons for specified user
	public static int GetPurchased( User user )
	{
		return user.Purchases.Sum( purchase => purchase.Count );
	}

	// Returns total number purchased Team-Seasons that have been used
	public static int GetUsed( User user )
	{
		return user.Purchases.Sum( purchase => purchase.Used );
	}

	// Returns total number purchased Team-Seasons still available for use
	public static int GetRemaining( User user )
	{
		int purchased = GetPurchased( user );
		int used = GetUsed( user );

		return (purchased - used);
	}

	// Determines if specified user has Team-Season license(s) available
	public static bool HasAvailable( User user )
	{
		return (GetRemaining( user ) > 0);
	}

	// Handles pending purchases
	public static async Task HandlePending( User user )
	{
		if ( DXData.HasConnection() )
		{
			DXBillingPurchase pending = DXBilling.GetPending();

			// Payment waiting to be processed
			if ( pending != null )
			{
				DXBillingPurchase purchase = await DXBilling.CompletePurchase( pending, DXBilling.ProductType.Consumable );

				// Purchase now complete, grant access
				if ( purchase != null )
				{
					string productId = purchase.ProductId;
					string purchaseId = purchase.PurchaseId;

					int count = Purchase.GetCount( productId );

					await Record( user, productId, purchaseId, count );
				}
			}
		}
	}

	/* Free Trial */

	// Determines if free trial already used to create Team-Season
	public static bool IsTrialUsed( User user )
	{
		return user.TrialStarted.HasValue;
	}

	// Determines if specified user is within free trial period
	public static bool IsTrialPeriod( User user )
	{
		DateTimeOffset? started = user.TrialStarted;

		// Trial period was started
		if ( started.HasValue )
		{
			TimeSpan elapsed = DateTimeOffset.Now.Subtract( (DateTimeOffset)started );

			// Must still be within trial period
			return TrialDuration.Subtract( elapsed ).TotalMinutes > 0;
		}

		return false;
	}
}

//
