using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEngine;
using Arkadium.Interop;
using Newtonsoft.Json;

namespace Arkadium
{
    [Serializable]
    public class WalletInventoryItem
    {
        public string sku;
        public int amount;
    }

    [Serializable]
    public class WalletBundle
    {
        public string sku;
        public int price;
        public int salesPrice;
        public string salesEndDate;
        public bool isSalesActive;
        public WalletInventoryItem[] contents;
    }

    public interface IArkadiumWalletV2
    {
        Task<bool> IsGemsSupportedAsync();
        Task<int> GetGemsAsync();
        Task<bool> ConsumeGemsAsync(int value);
        Task<Dictionary<string, WalletInventoryItem>> GetInventoryAsync();
        Task<int> GetInventoryItemAmountAsync(string sku);
        Task<bool> ConsumeInventoryItemAsync(string sku, int amount = 1);
        Task<bool> HasInventoryItemAsync(string sku, int amount = 1);
        Task<Dictionary<string, WalletBundle>> GetBundlesAsync();
        Task<bool> PurchaseBundleAsync(string bundleSku, int amount = 1);
        Task<Dictionary<string, WalletInventoryItem>> GetCatalogAsync();
        Task<bool> GrantCatalogItemAsync(string itemSku, int amount = 1);

        // Legacy callback-based methods for backward compatibility
        void IsGemsSupported(Action<bool> cb);
        void GetGems(Action<int> cb);
        void ConsumeGems(int value, Action<bool> cb);
        void GetInventory(Action<Dictionary<string, WalletInventoryItem>> cb);
        void GetInventoryItemAmount(string sku, Action<int> cb);
        void ConsumeInventoryItem(string sku, Action<bool> cb);
        void ConsumeInventoryItem(string sku, int amount, Action<bool> cb);
        void HasInventoryItem(string sku, Action<bool> cb);
        void HasInventoryItem(string sku, int amount, Action<bool> cb);
        void GetBundles(Action<Dictionary<string, WalletBundle>> cb);
        void PurchaseBundle(string bundleSku, Action<bool> cb);
        void PurchaseBundle(string bundleSku, int amount, Action<bool> cb);
        void GetCatalog(Action<Dictionary<string, WalletInventoryItem>> cb);
        void GrantCatalogItem(string itemSku, Action<bool> cb);
        void GrantCatalogItem(string itemSku, int amount, Action<bool> cb);
    }

    public class ArkadiumWalletV2 : IArkadiumWalletV2
    {
        /// <summary>
        /// Check if gems are supported using async/await
        /// </summary>
        public async Task<bool> IsGemsSupportedAsync()
        {
            try
            {
                var result = await WebGLInterop.InvokeAsync<bool>("wallet.isGemsSupported");
                return result;
            }
            catch (Exception ex)
            {
                Debug.LogError($"Error checking if gems are supported: {ex.Message}");
                return false;
            }
        }

        /// <summary>
        /// Get current gems count using async/await
        /// </summary>
        public async Task<int> GetGemsAsync()
        {
            try
            {
                var result = await WebGLInterop.InvokeAsync<int>("wallet.getGems");
                return result;
            }
            catch (Exception ex)
            {
                Debug.LogError($"Error getting gems: {ex.Message}");
                return -1;
            }
        }

        /// <summary>
        /// Consume gems using async/await
        /// </summary>
        public async Task<bool> ConsumeGemsAsync(int value)
        {
            try
            {
                var result = await WebGLInterop.InvokeAsync<bool>("wallet.consumeGems", new { value });
                return result;
            }
            catch (Exception ex)
            {
                Debug.LogError($"Error consuming gems: {ex.Message}");
                return false;
            }
        }

        /// <summary>
        /// Get wallet inventory using async/await
        /// </summary>
        public async Task<Dictionary<string, WalletInventoryItem>> GetInventoryAsync()
        {
            try
            {
                var result = await WebGLInterop.InvokeAsync<string>("wallet.getInventory");
                if (string.IsNullOrEmpty(result) || result == "[]" || result == "null")
                    return new Dictionary<string, WalletInventoryItem>();

                var inventory = JsonConvert.DeserializeObject<Dictionary<string, WalletInventoryItem>>(result);
                return inventory ?? new Dictionary<string, WalletInventoryItem>();
            }
            catch (Exception ex)
            {
                Debug.LogError($"Error getting inventory: {ex.Message}");
                return new Dictionary<string, WalletInventoryItem>();
            }
        }

        /// <summary>
        /// Get wallet inventory item amount by SKU using async/await
        /// </summary>
        public async Task<int> GetInventoryItemAmountAsync(string sku)
        {
            try
            {
                var result = await WebGLInterop.InvokeAsync<int>("wallet.getInventoryItemAmount", new object[] { sku });
                return result;
            }
            catch (Exception ex)
            {
                Debug.LogError($"Error getting inventory item amount: {ex.Message}");
                return 0;
            }
        }

        /// <summary>
        /// Consume a wallet inventory item using async/await
        /// </summary>
        public async Task<bool> ConsumeInventoryItemAsync(string sku, int amount = 1)
        {
            try
            {
                var result = await WebGLInterop.InvokeAsync<bool>("wallet.consumeInventoryItem", new object[] { sku, amount });
                return result;
            }
            catch (Exception ex)
            {
                Debug.LogError($"Error consuming inventory item: {ex.Message}");
                return false;
            }
        }

        /// <summary>
        /// Check if the wallet has an inventory item using async/await
        /// </summary>
        public async Task<bool> HasInventoryItemAsync(string sku, int amount = 1)
        {
            try
            {
                var result = await WebGLInterop.InvokeAsync<bool>("wallet.hasInventoryItem", new object[] { sku, amount });
                return result;
            }
            catch (Exception ex)
            {
                Debug.LogError($"Error checking inventory item: {ex.Message}");
                return false;
            }
        }

        /// <summary>
        /// Get wallet bundles using async/await
        /// </summary>
        public async Task<Dictionary<string, WalletBundle>> GetBundlesAsync()
        {
            try
            {
                var result = await WebGLInterop.InvokeAsync<string>("wallet.getBundles");
                if (string.IsNullOrEmpty(result) || result == "[]" || result == "null")
                    return new Dictionary<string, WalletBundle>();

                var bundles = JsonConvert.DeserializeObject<Dictionary<string, WalletBundle>>(result);
                return bundles ?? new Dictionary<string, WalletBundle>();
            }
            catch (Exception ex)
            {
                Debug.LogError($"Error getting bundles: {ex.Message}");
                return new Dictionary<string, WalletBundle>();
            }
        }

        /// <summary>
        /// Purchase a wallet bundle using async/await
        /// </summary>
        public async Task<bool> PurchaseBundleAsync(string bundleSku, int amount = 1)
        {
            try
            {
                var result = await WebGLInterop.InvokeAsync<bool>("wallet.purchaseBundle", new object[] { bundleSku, amount });
                return result;
            }
            catch (Exception ex)
            {
                Debug.LogError($"Error purchasing bundle: {ex.Message}");
                return false;
            }
        }

        /// <summary>
        /// Get wallet catalog using async/await
        /// </summary>
        public async Task<Dictionary<string, WalletInventoryItem>> GetCatalogAsync()
        {
            try
            {
                var result = await WebGLInterop.InvokeAsync<string>("wallet.getCatalog");
                if (string.IsNullOrEmpty(result) || result == "[]" || result == "null")
                    return new Dictionary<string, WalletInventoryItem>();

                var catalog = JsonConvert.DeserializeObject<Dictionary<string, WalletInventoryItem>>(result);
                return catalog ?? new Dictionary<string, WalletInventoryItem>();
            }
            catch (Exception ex)
            {
                Debug.LogError($"Error getting catalog: {ex.Message}");
                return new Dictionary<string, WalletInventoryItem>();
            }
        }

        /// <summary>
        /// Grant a wallet catalog item using async/await
        /// </summary>
        public async Task<bool> GrantCatalogItemAsync(string itemSku, int amount = 1)
        {
            try
            {
                var result = await WebGLInterop.InvokeAsync<bool>("wallet.grantCatalogItem", new object[] { itemSku, amount });
                return result;
            }
            catch (Exception ex)
            {
                Debug.LogError($"Error granting catalog item: {ex.Message}");
                return false;
            }
        }

        // Legacy callback-based methods for backward compatibility
        public void IsGemsSupported(Action<bool> cb)
        {
            _ = InvokeAsyncCallback(async () =>
            {
                var result = await IsGemsSupportedAsync();
                cb?.Invoke(result);
            });
        }

        public void GetGems(Action<int> cb)
        {
            _ = InvokeAsyncCallback(async () =>
            {
                var result = await GetGemsAsync();
                cb?.Invoke(result);
            });
        }

        public void ConsumeGems(int value, Action<bool> cb)
        {
            _ = InvokeAsyncCallback(async () =>
            {
                var result = await ConsumeGemsAsync(value);
                cb?.Invoke(result);
            });
        }

        public void GetInventory(Action<Dictionary<string, WalletInventoryItem>> cb)
        {
            _ = InvokeAsyncCallback(async () =>
            {
                var result = await GetInventoryAsync();
                cb?.Invoke(result);
            });
        }

        public void GetInventoryItemAmount(string sku, Action<int> cb)
        {
            _ = InvokeAsyncCallback(async () =>
            {
                var result = await GetInventoryItemAmountAsync(sku);
                cb?.Invoke(result);
            });
        }

        public void ConsumeInventoryItem(string sku, Action<bool> cb)
        {
            _ = InvokeAsyncCallback(async () =>
            {
                var result = await ConsumeInventoryItemAsync(sku);
                cb?.Invoke(result);
            });
        }

        public void ConsumeInventoryItem(string sku, int amount, Action<bool> cb)
        {
            _ = InvokeAsyncCallback(async () =>
            {
                var result = await ConsumeInventoryItemAsync(sku, amount);
                cb?.Invoke(result);
            });
        }

        public void HasInventoryItem(string sku, Action<bool> cb)
        {
            _ = InvokeAsyncCallback(async () =>
            {
                var result = await HasInventoryItemAsync(sku);
                cb?.Invoke(result);
            });
        }

        public void HasInventoryItem(string sku, int amount, Action<bool> cb)
        {
            _ = InvokeAsyncCallback(async () =>
            {
                var result = await HasInventoryItemAsync(sku, amount);
                cb?.Invoke(result);
            });
        }

        public void GetBundles(Action<Dictionary<string, WalletBundle>> cb)
        {
            _ = InvokeAsyncCallback(async () =>
            {
                var result = await GetBundlesAsync();
                cb?.Invoke(result);
            });
        }

        public void PurchaseBundle(string bundleSku, Action<bool> cb)
        {
            _ = InvokeAsyncCallback(async () =>
            {
                var result = await PurchaseBundleAsync(bundleSku);
                cb?.Invoke(result);
            });
        }

        public void PurchaseBundle(string bundleSku, int amount, Action<bool> cb)
        {
            _ = InvokeAsyncCallback(async () =>
            {
                var result = await PurchaseBundleAsync(bundleSku, amount);
                cb?.Invoke(result);
            });
        }

        public void GetCatalog(Action<Dictionary<string, WalletInventoryItem>> cb)
        {
            _ = InvokeAsyncCallback(async () =>
            {
                var result = await GetCatalogAsync();
                cb?.Invoke(result);
            });
        }

        public void GrantCatalogItem(string itemSku, Action<bool> cb)
        {
            _ = InvokeAsyncCallback(async () =>
            {
                var result = await GrantCatalogItemAsync(itemSku);
                cb?.Invoke(result);
            });
        }

        public void GrantCatalogItem(string itemSku, int amount, Action<bool> cb)
        {
            _ = InvokeAsyncCallback(async () =>
            {
                var result = await GrantCatalogItemAsync(itemSku, amount);
                cb?.Invoke(result);
            });
        }

        /// <summary>
        /// Helper method to properly handle async callbacks in Unity WebGL
        /// </summary>
        private async Task InvokeAsyncCallback(Func<Task> asyncOperation)
        {
            try
            {
                await asyncOperation();
            }
            catch (Exception ex)
            {
                Debug.LogError($"Error in async callback: {ex.Message}");
            }
        }
    }
}
