using System;
using System.Linq;
using I2.Loc;
using MyGame.Scenes.Cooking.Scripts;
using MyGame.Scripts;
using TMPro;
using UniRx;
using UnityEngine;
using UnityEngine.UI;
using Random = UnityEngine.Random;

public class CookingResult : MonoBehaviour
{
    private static readonly string QuantityTextFormat = "x{0}";
    private static readonly float BulkOrderExplainHeight = 200f;
    [SerializeField] private GameObject smokeEffect;
    [SerializeField] private GameObject glitterEffect;
    [SerializeField] private Button perfectButton;
    [SerializeField] private Button okButton;
    [SerializeField] private Button destructionButton;
    [SerializeField] private Button makeOneButton;
    [SerializeField] private Transform popcornTarget;
    [SerializeField] private Text popcornText;
    [SerializeField] private Text popcornTextPerfect;
    [SerializeField] private TextMeshProUGUI quantityText;
    [SerializeField] private Text rarityText;
    [SerializeField] private RarityView rarityView;
    [SerializeField] private GameObject detailObject;
    [SerializeField] private GameObject explainObject;
    [SerializeField] private GameObject explainWithRarityObject;
    [SerializeField] private GameObject perfectResultObject;
    [SerializeField] private GameObject goodResultObject;
    [SerializeField] private GameObject failureResultObject;
    [SerializeField] private ResultCoinView coinView;

    ReactiveProperty<CornResult> result = new ReactiveProperty<CornResult>();
   
    private void Start()
    {
        result.AddTo(this);
        SoundManager.Instance.ChangeVolumeUniqueBGM(.3f);
        
        var viewType = LocalCacheManager.Load(Const.ProductViewTypeTag, ProductViewType.Default);
        var productData = LocalCacheManager.Load<ProductData>(PopcornGameManager.CookingDataTag);
        var (rarityData, resultData, successAction) = LocalCacheManager.Load<(RarityData, CornResult, Action)>(PopcornGameManager.CookingResultDataTag);
        result.Value = resultData;
        SetData(productData, rarityData, viewType);
        
        // 材料消費&仮獲得
        RecipeDetailView.ConsumeMaterial(productData);
        if (viewType == ProductViewType.Default)
        {
            result.Subscribe(cornResult =>
            {
                // 仮獲得データ登録
                GameDataManager.GameData.WaitAddStock.FlavorId = productData.id;
                GameDataManager.GameData.WaitAddStock.Stock = cornResult == CornResult.Failure ? 0 : productData.volume;
                GameDataManager.GameData.WaitAddStock.Rarity = cornResult == CornResult.Perfect ? rarityData.Rarity : ProductRarity.Normal;
                GameDataManager.SaveGameData();
            }).AddTo(this);
        }
        else
        {
            // 大量注文時処理
            var materialNumber = LocalCacheManager.Load<int>(BulkOrder.MaterialNumberTag);
            result.Where(x => x != CornResult.Failure ).Subscribe(cornResult =>
            {
                if (!(GameDataManager.GameData.CompletedProductList.FirstOrDefault(data => data.Number == materialNumber) is BulkOrderResultData bulkOrderResultData))
                {
                    bulkOrderResultData = new BulkOrderResultData
                    {
                        Number = materialNumber
                    };
                    GameDataManager.GameData.CompletedProductList.Add(bulkOrderResultData);
                }
                // レア上書き
                bulkOrderResultData.Rarity = cornResult == CornResult.Perfect ? rarityData.Rarity : ProductRarity.Normal;
                GameDataManager.SaveGameData();
            }).AddTo(this);
        }

        // チュートリアル時
        if (!GameDataManager.GameData.FinishedFlags.HasFlag(TutorialFlag.FirstPlay))
        {
            // ボタン非表示
            SetUI(resultData, viewType, CheckMakeOne(resultData, productData), true);
            
            // 失敗したら再チャレンジ
            if (resultData == CornResult.Failure)
            {
                Observable.Timer(TimeSpan.FromSeconds(1.25f)).Subscribe(_ =>
                {
                    TutorialManager.Instance.ShowTutorialConversation(2, () =>
                    {
                        SoundManager.Instance.ChangeVolumeUniqueBGM(1f);
                        TransitionManager.Instance.UnloadScene(GameScenes.CookingResults);
                        LocalCacheManager.Load<Action>(PopcornGameManager.RestartCallbackTag, null)?.Invoke();
                    });
                }).AddTo(this);
                return;
            }
            
            // ボタン表示
            successAction?.Invoke();
            okButton.gameObject.SetActive(true);
            okButton.OnClickAsObservable().Take(1).Subscribe(_ =>
            {
                // 獲得、遷移
                MoveStock(GameDataManager.GameData.WaitAddStock);
                GameDataManager.SaveGameData();
                TransitionManager.Instance.LoadScene(GameScenes.Main);
            }).AddTo(this);
            return;
        }
        
        // UI用
        result.Subscribe(cornResult =>
        {
            SetUI(cornResult, viewType, CheckMakeOne(cornResult, productData));
            if (cornResult != CornResult.Failure)
            {
                successAction?.Invoke();
            }
        }).AddTo(this);
        
        // 大成功にする
        perfectButton.OnClickAsObservable().ThrottleFirst(TimeSpan.FromSeconds(.3f)).Subscribe(_ =>
        {
            // 広告視聴後、結果上書き
            GetRewardDialog.ShowPerfectPopcornDialog(() =>
            {
                result.Value = CornResult.Perfect;
            });
        }).AddTo(this);

        // 獲得する
        if (viewType == ProductViewType.Default)
        {
            Market.Instance.IsPause.Value = true;
            okButton.OnClickAsObservable().Take(1).Subscribe(_ =>
            {
                // 獲得、遷移
                MoveStock(GameDataManager.GameData.WaitAddStock);
                
                // 確率でVip宣伝
                if (GameDataManager.GameData.ShopStock.Count >= Const.VipCustomerRewardStock)
                {
                    if (Random.value <= Const.VipCustomerRewardRate)
                    {
#if UNITY_EDITOR
                        Debug.Log($"flag VipReward");
#endif
                        GameDataManager.GameData.vipCustomerFirstOpen = true;
                        GameDataManager.GameData.vipCustomerLimitTime = DateTime.UtcNow.AddSeconds(60).ToBinary();
                    }
                }
                GameDataManager.SaveGameData();
                Market.Instance.IsPause.Value = false;
                TransitionManager.Instance.LoadScene(GameScenes.Main);
            }).AddTo(this);
            
            // もう一度作る
            makeOneButton.OnClickAsObservable().Take(1).Subscribe(_ =>
            {
                // 獲得、遷移
                MoveStock(GameDataManager.GameData.WaitAddStock);
                GameDataManager.SaveGameData();
                Market.Instance.IsPause.Value = false;
                SoundManager.Instance.ChangeVolumeUniqueBGM(1f);
                TransitionManager.Instance.UnloadScene(GameScenes.CookingResults);
                LocalCacheManager.Load<Action>(PopcornGameManager.RestartCallbackTag, null)?.Invoke();
            }).AddTo(this);
        }
        else
        {
            // 大量注文時処理
            okButton.OnClickAsObservable().Take(1).Subscribe(_ =>
            {
                TransitionManager.Instance.LoadScene(GameScenes.Main);
            }).AddTo(this);
        }

        // 破棄する
        destructionButton.OnClickAsObservable().Take(1).Subscribe(_ =>
        {
            TransitionManager.Instance.LoadScene(GameScenes.Main);
        }).AddTo(this);
    }

    private void SetData(ProductData recipe, RarityData rarity, ProductViewType viewType)
    {
        // popcornImage
        popcornText.text = recipe.Name;
        popcornTextPerfect.text = recipe.Name;
        quantityText.text = string.Format(QuantityTextFormat, recipe.volume);
        coinView.SetPrice(recipe.GetRarityPrice(ProductRarity.Normal), recipe.GetRarityPrice(rarity.Rarity));
        var rarityFormat = viewType == ProductViewType.Default ? rarity.Text : ScriptLocalization.UI.CookingResultsBulkOrderPerfect;
        rarityText.text = rarityFormat;
        rarityView.SetRarity(rarity.Rarity);
        popcornTarget.DestroyAllChildrens();
        Instantiate(recipe.GetLargePrefab(), popcornTarget);
    }
    
    private void SetUI(CornResult cornResult, ProductViewType viewType, bool isMakeOne, bool isTutorial = false)
    {
        perfectButton.gameObject.SetActive(false);
        okButton.gameObject.SetActive(false);
        destructionButton.gameObject.SetActive(false);
        makeOneButton.gameObject.SetActive(false);

        if (!isTutorial)
        {
            this.CallWaitForSeconds(1.25f, () =>
            {
                makeOneButton.gameObject.SetActive(viewType == ProductViewType.Default && isMakeOne);
                perfectButton.gameObject.SetActive(cornResult != CornResult.Perfect);
                destructionButton.gameObject.SetActive(cornResult == CornResult.Failure);
                okButton.gameObject.SetActive(cornResult != CornResult.Failure);
            });
        }

        perfectResultObject.SetActive(cornResult == CornResult.Perfect);
        goodResultObject.SetActive(cornResult == CornResult.Good);
        failureResultObject.SetActive(cornResult == CornResult.Failure);

        if (cornResult == CornResult.Failure)
        {
            VibrationManager.Instance.PlayVibrationDoubleStrong();
        }
        smokeEffect.SetActive(cornResult == CornResult.Failure);
        glitterEffect.SetActive(cornResult == CornResult.Perfect);

        detailObject.SetActive(cornResult != CornResult.Failure);
        explainObject.SetActive(cornResult == CornResult.Good);
        explainWithRarityObject.SetActive(cornResult == CornResult.Perfect);

        if (viewType != ProductViewType.Default)
        {
            coinView.gameObject.SetActive(false);
            // 高さ調整
            var rect = explainWithRarityObject.transform as RectTransform;
            rect.sizeDelta = new Vector2(rect.sizeDelta.x, BulkOrderExplainHeight);
        }
    }

    // 続けて料理を作ることができるかどうか判定
    private bool CheckMakeOne(CornResult cornResult, ProductData productData)
    {
        ProductData doubleProductData = productData;
        if (cornResult != CornResult.Failure)
        {
            // まだ在庫追加前なのでレシピvolumeを２倍にしてタンクの空きを確認
            doubleProductData = new ProductData(productData, 1){volume = productData.volume * 2};
        }
        var hasSpace = RecipeDetailView.CheckTank(doubleProductData);
        //素材確認
        var checkResult = RecipeDetailView.CheckAmount(productData);
        var hasMaterials = checkResult.material1 && checkResult.material2 && checkResult.material3;
        return hasSpace && hasMaterials;
    }

    public static void MoveStock(ProductStockData productStockData)
    {
        AddStock(productStockData);
        productStockData.Stock = 0;
    }

    public static void AddStock(ProductData productData, ProductRarity rarity = ProductRarity.Normal)
    {
        AddStock(new ProductStockData{FlavorId = productData.id, Stock = productData.volume, Rarity = rarity});
        GameDataManager.SaveGameData();
    }

    public static void AddStock(ProductStockData productStockData)
    {
        if (productStockData.Stock == 0)
        {
            return;
        }
        var gameData = GameDataManager.GameData;
        // 店頭の空きに追加
        var remain = productStockData.Stock;
        var shopSpace = Market.ShopStockCount - gameData.ShopStock.Count;
        var stockCount = Mathf.Min(shopSpace, remain);
        gameData.ShopStock.AddRange(Enumerable.Repeat(new ProductStockData
        {
            FlavorId = productStockData.FlavorId,
            Rarity = productStockData.Rarity,
        }, stockCount));
        remain -= stockCount;
        // ShopStockに補充された場合、DisplayFlavors更新
        if (stockCount > 0)
        {
            Market.Instance.RefillDisplayFlavors(gameData.ShopStock);
            Market.Instance.CheckStock(gameData.ShopStock);
        }

        // 空タンク並び替え
        gameData.StorageTanks = gameData.StorageTanks.OrderBy(tank => tank.IsEmpty).ToList();
        // 空きのタンクを確認
        gameData.StorageTanks
            .Select((tank, i) => (tank, i))
            .Where(x => x.tank.IsEmpty || x.tank.FlavorId == productStockData.FlavorId && !x.tank.IsFull)
            .Select(x => (x.i, space: x.tank.Capacity - x.tank.Stock))
            .OrderBy(x => x.space)
            .ToList()
            .ForEach(x =>
            {
                if (remain == 0)
                {
                    return;
                }
                // タンクが空ならフレーバー設定
                if (gameData.StorageTanks[x.i].IsEmpty)
                {
                    gameData.StorageTanks[x.i].FlavorId = productStockData.FlavorId;
                }
                // タンクに追加
                stockCount = Mathf.Min(x.space, remain);
                gameData.StorageTanks[x.i].AddStock(productStockData.Rarity, stockCount);
                remain -= stockCount;
            });
    }
}

