using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using MyGame.Scripts;
using UniRx;
using UnityEngine;

public class Shopping : MonoBehaviour
{
    [SerializeField] private ShopListView listView;
    [SerializeField] private GameObject recipeNotifyIcon;
    
    // Start is called before the first frame update
    private Subject<int> changeCoinSubject = new Subject<int>();
    void Start()
    {
        changeCoinSubject.AddTo(this);
        
        SoundManager.Instance.PlayBGM("bgm_shopping");
        var gameData = GameDataManager.GameData;
        
        // 一覧データ
        var shopDataList = SpreadsheetDataManager.Instance.GetBaseDataList<ShopData>(Const.ShopDataSheet);
        
        // tutorial 所持金が指定アイテムの金額以上かどうかチェック
        var isTutorial = false;
        if (!gameData.FinishedFlags.HasFlag(TutorialFlag.Shopping))
        {
            if (gameData.Coin >= (shopDataList.FirstOrDefault(data => data.itemId == 2)?.price ?? 10))
            {
                isTutorial = true;
            }
        }

        CoinManager.Instance.ChangeCoin(gameData.Coin);
        HeartMeter.Instance.Initialize(gameData.ViewedShopLevel, gameData.Heart);
        
        // ハートゲージがフルかつダイアログが開いていない場合レベルアップ
        HeartMeter.Instance.FulledHeart
            .DelaySubscription(TimeSpan.FromSeconds(.4f))
            .Subscribe(_ =>
            {
                ShopLevelUp.ShowDialog(gameData.ViewedShopLevel + 1);
            }).AddTo(this);

        GameDataObserver.Instance.HeartObserver
            .DistinctUntilChanged()
            .Pairwise()
            .Subscribe(pair =>
            {
                HeartMeter.Instance.AddHeart(pair.Current - pair.Previous);
            }).AddTo(this);
        
        foreach (var shopData in shopDataList)
        {
            if (shopData.Category == ItemCategory.Special)
            {
                continue;
            }
            var itemView = listView.AddItemView(shopData);
            itemView.SetData(shopData);
            itemView.SetStockCount(GetItemAmount(shopData));
            // コインを監視して購入可能状態を切り替え
            changeCoinSubject.Subscribe(ownCoin =>
            {
                itemView.SetItemActive(shopData.price <= ownCoin);
            }).AddTo(this);
            // アイテム購入クリック購読
            itemView.PurchaseButtonObservable
                .ThrottleFirst(TimeSpan.FromSeconds(.3f))
                .Where(_ => shopData.price <= CoinManager.Instance.OwnCoin)
                .Subscribe(_ =>
                {
                    ShopItemPurchaseView.ShowDialog((shopData, GetItemAmount(shopData)), amount =>
                    {
                        // アイテムを増やす
                        AddItem(shopData, amount);
                        itemView.SetStockCount(GetItemAmount(shopData));
                        CoinManager.Instance.SubCoin(shopData.price * amount);
                        gameData.Coin = CoinManager.Instance.OwnCoin;
                        changeCoinSubject.OnNext(gameData.Coin);
                        GameDataManager.SaveGameData();
                        
                        if (isTutorial)
                        {
                            TutorialManager.Instance.ShowTutorialConversation(8, () =>
                            {
                                isTutorial = false;
                                gameData.FinishedFlags |= TutorialFlag.Shopping;
                                GameDataManager.SaveGameData();
                            });
                        }
                    });
                }).AddTo(itemView);
            
            // 広告視聴獲得
            itemView.ExchangeButtonObservable
                .ThrottleFirst(TimeSpan.FromSeconds(.3f))
                .Subscribe(_ =>
                {
                    ShopItemExchangeView.ShowDialog(shopData, () =>
                    {
                        // アイテムを増やす
                        AddItem(shopData, 1);
                        itemView.SetStockCount(GetItemAmount(shopData));
                        GameDataManager.SaveGameData();
                        recipeNotifyIcon.SetActive(CheckEarnedRecipe());
                    });
                }).AddTo(itemView);
            
            // show detail view
            itemView.DetailButtonObservable.ThrottleFirst(TimeSpan.FromSeconds(.3f)).Subscribe(_ =>
            {
                LocalCacheManager.Save(ShopItemDetailView.ItemDetailTag, shopData);
                TransitionManager.Instance.LoadSceneAdditive(GameScenes.ShoppingExplanation);
            }).AddTo(itemView);
        }
        listView.SetTab(ItemCategory.Material);
        changeCoinSubject.OnNext(CoinManager.Instance.OwnCoin);
        
        recipeNotifyIcon.SetActive(CheckEarnedRecipe());
        
        if (isTutorial)
        {
            listView.ScrollRect.vertical = false;
            TutorialManager.Instance.ShowTutorialConversation(7, () =>
            {
                // マスク表示
                var view = listView.ScrollRect.content.GetChild(0).GetComponent<ShopItemView>();
                var viewRectTransform = view.transform as RectTransform;
                var go = TutorialManager.Instance.ShowTutorialMask(listView.transform.parent, viewRectTransform);
                view.PurchaseButtonObservable.Take(1).Subscribe(_ =>
                {
                    DestroyImmediate(go);
                }).AddTo(this);
            });
        }
    }

    private static int GetItemAmount(ShopData shopData)
    {
        var gameData = GameDataManager.GameData;
        switch (shopData.Category)
        {
            case ItemCategory.Material:
                return gameData.Material.Find(data => data.Id == shopData.itemId)?.Amount ?? 0;
            case ItemCategory.Recipe:
                return gameData.MyRecipes.Contains(shopData.itemId) ? 1 : 0;
            case ItemCategory.Pan:
                return gameData.Pans.Contains(shopData.itemId) ? 1 : 0;
            default:
                throw new ArgumentOutOfRangeException();
        }
    }

    public static void AddItem(ShopData shopData, int amount)
    {
        var gameData = GameDataManager.GameData;
        switch (shopData.Category)
        {
            case ItemCategory.Material:
                var index = gameData.Material.FindIndex(x => x.Id == shopData.itemId);
                if (index == -1)
                {
                    index = gameData.Material.Count;
                    gameData.Material.Add(new MaterialData
                    {
                        Id = shopData.itemId,
                        Amount = 0
                    });
                }
                gameData.Material[index].Amount += amount;
                break;
            case ItemCategory.Recipe:
                if (!gameData.MyRecipes.Contains(shopData.itemId))
                {
                    gameData.MyRecipes = new List<int>(gameData.MyRecipes){shopData.itemId}.ToArray();
                    gameData.DailyRecipeGetCount++;
                }
                break;
            case ItemCategory.Pan:
                if (!gameData.Pans.Contains(shopData.itemId))
                {
                    gameData.Pans = new List<int>(gameData.Pans){shopData.itemId}.ToArray();
                }
                break;
            default:
                throw new ArgumentOutOfRangeException();
        }
    }

    public static bool CheckEarnedRecipe()
    {
        var shopDataList = SpreadsheetDataManager.Instance.GetBaseDataList<ShopData>(Const.ShopDataSheet);
        var adCount = GameDataManager.GameData.adCount;
        foreach (var shopData in shopDataList.Where(data => data.Category == ItemCategory.Recipe))
        {
            if (GetItemAmount(shopData) > 0) continue;
            if (shopData.price <= adCount)
            {
                return true;
            }
        }

        return false;
    }
}
