using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using MyGame.Scenes.CornField.Scripts;
using MyGame.Scripts;
using UniRx;
using UnityEngine;
using UnityEngine.UI;
using Random = UnityEngine.Random;

public enum CornFieldRank
{
    Rank1,
    Rank2,
    Rank3
}

public class CornField : MonoBehaviour
{
    [SerializeField] private float animationDuration = .3f;
    [SerializeField] private float fertilizerFinishWaitTime = 1f;
    [SerializeField] private int cornSortingOrder = 40;
    [Space] 
    [SerializeField] private UIVisibleController uiVisibleController;
    [SerializeField] private GameObject sideButtons;
    [SerializeField] private Button promoteGrowthButton;
    [SerializeField] private Button upgradeButton;
    [SerializeField] private GameObject upgradeButtonBadge;
    [SerializeField] private GameObject harvestEffectPrefab;
    [SerializeField] private GameObject harvestPrefab;
    [SerializeField] private Transform harvestSpawnTarget;
    [SerializeField] private Transform harvestInsertPosition;
    [SerializeField] private CornHarvester cornHarvester;
    [SerializeField] private FertilizerButtonView fertilizerButtonView;
    [SerializeField] private BrotherFertilizerAnimation brotherFertilizerAnimation;
    [SerializeField] private HarvestedCounterView counterView;
    [SerializeField] private HarvestedAdditionView additionView;
    [SerializeField] private Transform animationTarget;
    [Space]
    [SerializeField] private List<PlantLine> plantLines = new List<PlantLine>();
    [Space] [SerializeField] private TutorialObjectMask cornFieldMask;
    
    private static readonly int maxPeriod = 60;
    private static readonly int minPeriod = 45;
    private static readonly int harvestedFrameInterval = 3;
    private static readonly float harvestedDistance = .6f;
    private static readonly float countThrottle = .6f;
    private static readonly float animationStartDelay = .02f;
    private static readonly int animationDivisor = 3;
    private static readonly int animationLimit = 100;

    private static readonly int fertilizerDuration = 15;
    private static readonly double fertilizerWaitTime = 300f;
    
    private readonly CompositeDisposable compositeDisposable = new CompositeDisposable();
    private readonly Subject<int> resetFertilizerTimer = new Subject<int>();
    private bool isFertilizing;
    
    // Start is called before the first frame update
    void Start()
    {
        compositeDisposable.AddTo(this);
        resetFertilizerTimer.AddTo(this);

        SoundManager.Instance.PlayBGM("bgm_Main");
        // データ
        var gameData = GameDataManager.GameData;

        if (gameData.isFirstPlay)
        {
            promoteGrowthButton.gameObject.SetActive(false);
            TutorialManager.Instance.ShowTutorialConversation(3, () =>
            {
                // コーンスワイプ指示
                cornFieldMask.gameObject.SetActive(true);
            });
        }
        else
        {
            cornFieldMask.gameObject.SetActive(false);
        }
        
        CoinManager.Instance.ChangeCoin(gameData.Coin);
        HeartMeter.Instance.Initialize(gameData.ViewedShopLevel, gameData.Heart);
        GameDataObserver.Instance.ShopLevelUpdate
            .Where(x => x && !isFertilizing)
            .Subscribe(x =>
            {
                LocalCacheManager.Save(ShopLevelUp.DataTag, gameData.ViewedShopLevel + 1);
                TransitionManager.Instance.LoadSceneAdditive(GameScenes.StoreLevel);
            }).AddTo(this);
        counterView.Initialize(gameData.CornSeed);
        additionView.Initialize(0);
        SetData();

        // 畑リセット
        foreach (var line in plantLines)
        {
            line.gameObject.SetActive(false);
        }

        SetCornField();

        upgradeButton.OnClickAsObservable().ThrottleFirst(TimeSpan.FromSeconds(.3f)).Subscribe(_ =>
        {
            CornFieldReinforcement.ShowDialog(() => SetCornField());
        }).AddTo(this);
        
        fertilizerButtonView.RewardButton.ThrottleFirst(TimeSpan.FromSeconds(.3f)).Subscribe(_ =>
        {
            GetRewardDialog.ShowCornFieldDialog(() =>
            {
                gameData.fertilizerTime = DateTime.UtcNow.AddSeconds(fertilizerWaitTime + fertilizerDuration).ToBinary();
#if UNITY_EDITOR
                gameData.fertilizerTime = DateTime.UtcNow.AddSeconds(10 + fertilizerDuration).ToBinary();
#endif
                GameDataManager.SaveGameData();
                
                isFertilizing = true;
                additionView.IsStopDisapper = true;
                SoundManager.Instance.PlayBGM("bgm_fertilizer");
                brotherFertilizerAnimation.StartAnimation();
                // button非表示
                promoteGrowthButton.gameObject.SetActive(false);
                sideButtons.SetActive(false);
                uiVisibleController.SetActive(false);
                
                SetCornField(true);
                
                var push = new Subject<Unit>().AddTo(this);
                // 既存の株は成長済みにする
                foreach (var plantLine in plantLines) 
                {
                    if (gameData.PlantLineDataList.FirstOrDefault(data => data.Type == plantLine.LineName) is PlantLineData plantLineData) 
                    {
                        for (int i = 0; i < plantLine.Seedlings.Count; i++)
                        {
                            var progressData = gameData.SeedlingDataList.First(data => data.type == plantLineData.Type).Seedlings[i];
                            var seedling = plantLine.Seedlings[i];
                            progressData.FirstTime = progressData.FirstTime.AddSeconds(-maxPeriod);
                            seedling.PromoteGrowth(progressData.FirstTime);
                            // エフェクト出すだけ
                            // push.Subscribe(unit =>
                            // {
                            //     if (Random.value < .5f)
                            //     {
                            //         seedling.PromoteGrowth(progressData.FirstTime);
                            //     }
                            // }).AddTo(this);
                            
                        }
                    }
                }
                Observable.Timer(TimeSpan.FromSeconds(1f), TimeSpan.FromSeconds(1f))
                    .Select(x => (int)(fertilizerDuration - x))
                    .TakeWhile(x => x > 0)
                    .Subscribe(x =>
                    {
                        push.OnNext(Unit.Default);
                    }, () =>
                    {
                        SoundManager.Instance.PlayBGM("bgm_Main");
                        brotherFertilizerAnimation.EndAnimation();
                        SetCornField();
                        resetFertilizerTimer.OnNext((int)DateTime.FromBinary(gameData.fertilizerTime).Subtract(DateTime.UtcNow).TotalSeconds);

                        this.CallWaitForSeconds(fertilizerFinishWaitTime, () =>
                        {
                            isFertilizing = false;
                            additionView.IsStopDisapper = false;
                            additionView.PlayEffect();
                            // ボタン表示復活
                            promoteGrowthButton.gameObject.SetActive(true);
                            sideButtons.SetActive(true);
                            uiVisibleController.SetActive(true);
                        });
                    }).AddTo(this);
            });
        }).AddTo(this);
        
        // 残り時間表示
        IDisposable timerDisposable = null;
        resetFertilizerTimer
            .Subscribe(x =>
            {
                timerDisposable?.Dispose();
                fertilizerButtonView.SetButtonActive(x <= 0);
                fertilizerButtonView.SetTime(x);
                timerDisposable = SetFertilizerTimer(x).AddTo(this);
            }).AddTo(this);
        
        // 残り時間を取得
        var remaining = (int)DateTime.FromBinary(gameData.fertilizerTime).Subtract(DateTime.UtcNow).TotalSeconds;
        resetFertilizerTimer.OnNext(remaining);

        Observable.EveryApplicationPause()
            .Where(pause => !pause)
            .Subscribe(_ =>
            {
                resetFertilizerTimer.OnNext((int) DateTime.FromBinary(gameData.fertilizerTime).Subtract(DateTime.UtcNow).TotalSeconds);
            }).AddTo(this);

        // 収穫カウンター+吸収演出
        cornHarvester.FinishHarvested
            .Scan((list, newList) => (list.count += newList.count, list.colliders.Concat(newList.colliders).ToList()))
            .Throttle(TimeSpan.FromSeconds(countThrottle))
            .Take(1)
            .RepeatUntilDestroy(this)
            .Subscribe(x =>
            {
                var colliders = x.colliders;
                // カゴ外のやつ分ける
                var destroyList = colliders.Where(c => c.enabled == false).ToList();
                var stayList = colliders.Except(destroyList).ToList();
                // 間引く
                var animationList = stayList.RandomChoose(animationLimit);
                // 間引かれた分は破棄
                var culledList = stayList.Except(animationList).ToList();
                var culledCount = 1;
                var culledDivisor = Mathf.CeilToInt((float)culledList.Count / animationLimit);
                culledList.ForEach(c => Destroy(c.gameObject, .01f * Mathf.FloorToInt((float)culledCount++ / culledDivisor)));
                destroyList.ForEach(c => Destroy(c.gameObject, 2f));
                var j = 0;
                animationList.ForEach(harvested =>
                {
                    this.CallWaitForSeconds(animationStartDelay * Mathf.FloorToInt((float)j++ / animationDivisor), () =>
                    {
                        harvested.enabled = false;
                        var spriteRenderer = harvested.GetComponentInChildren<SpriteRenderer>();
                        spriteRenderer.sortingOrder = cornSortingOrder;
                        // Layer 5:UI 決め打ち
                        spriteRenderer.gameObject.layer = 5;
                        var beginPos = harvested.transform.position;
                        this.CallLerp(animationDuration, f =>
                        {
                            harvested.transform.position = Vector2.Lerp(beginPos, animationTarget.position, f.EaseInQuadratic());
                        }, () =>
                        {
                            Destroy(harvested.gameObject);
                            additionView.PlayEffect();
                        });
                    });
                });
                this.CallWaitForSeconds(animationDuration, () =>
                {
                    additionView.AddHarvestedCount(x.count);
                });
            }).AddTo(this);
        var counterTotalCorn = gameData.CornSeed;
        additionView.EndObservable.Subscribe(addCount =>
        {
            counterTotalCorn += addCount;
            counterView.PlayEffect();
            counterView.SetHarvestedCount(counterTotalCorn);
        }).AddTo(this);
    }

    public void SetCornField(bool useFertilizer = false)
    {
        compositeDisposable.Clear();
        var gameData = GameDataManager.GameData;
        var fieldData = SpreadsheetDataManager.Instance.GetBaseDataList<FieldUpgradeData>(Const.FieldUpgradeDataSheet);
        var machineList = fieldData.Where(data => data.Type == CornFieldUpgradeType.Machine);
        cornHarvester.SetMachine(machineList.First(data => data.level == gameData.MachineLevel).GetPrefab());

        // コーン株の進行度初回データ作成
        foreach (var lineData in gameData.PlantLineDataList)
        {
            if (gameData.SeedlingDataList.Exists(data => data.type == lineData.Type))
            {
                continue;
            }
            var plantLine = plantLines.First(line => line.LineName == lineData.Type);
            gameData.SeedlingDataList.Add(new SeedlingProgressData
            {
                type = lineData.Type,
                Seedlings = Enumerable.Range(0, plantLine.Seedlings.Count).Select(_ => GenerateSeedlingGene(lineData.Level)).ToList()
            });
        }

        if (gameData.isFirstPlay)
        {
            // 既に収穫できる状態にする
            var plantLine = gameData.SeedlingDataList.First(data => data.type == PlantLineType.Center);
            foreach (var seedling in plantLine.Seedlings)
            {
                seedling.FirstTime = DateTime.MinValue;
            }

            Observable.Merge(plantLines.SelectMany(line => line.Seedlings).Select(seedling => seedling.Harvested))
                .Take(3)
                .Subscribe(_ => { }, () =>
                {
                    this.CallWaitForSeconds(4f, () =>
                    {
                        cornFieldMask.gameObject.SetActive(false);
                        TutorialManager.Instance.ShowTutorialConversation(4, () =>
                        {
                            // gameData.SeedlingDataList.Clear();
                            var go = FindObjectOfType<FooterManager>().transform;
                            go.transform.FindChildByName("Button_Purchasing", t =>
                            {
                                TutorialManager.Instance.ShowTutorialMask(go.parent, t as RectTransform, true);
                            });
                        });
                    });
                }).AddTo(compositeDisposable);
        }
        GameDataManager.SaveGameData();

        // セーブデータから畑を復元
        foreach (var plantLine in plantLines)
        {
            if (!(gameData.PlantLineDataList.FirstOrDefault(data => data.Type == plantLine.LineName) is PlantLineData plantLineData))
            {
                continue;
            }
            plantLine.gameObject.SetActive(true);
            plantLine.SetFieldLevel(plantLineData.Level);

                for (int i = 0; i < plantLine.Seedlings.Count; i++)
                {
                    var progressData = gameData.SeedlingDataList.First(data => data.type == plantLineData.Type).Seedlings[i];
                    var seedling = plantLine.Seedlings[i];
                    seedling.SetSeedlingGene(progressData.FirstTime, progressData.Period, progressData.Level);
#if DEVELOPMENT_BUILD || UNITY_EDITOR
                    if (UsayaStorageManager.LoadOrDefault(UsayaStorageFilename.Settings_Data, "DebugFastGrowing", false))
                    {
                        seedling.SetSeedlingGene(progressData.FirstTime, progressData.Period / 3, progressData.Level);
                    }
#endif
                // 収穫通知
                seedling.Harvested.Subscribe(_ =>
                {
                    VibrationManager.Instance.PlayVibrationOnce();
                    var harvestCount = fieldData.FirstOrDefault(x => x.Type == CornFieldUpgradeType.FieldCenter && x.level == (int)progressData.Level)?.harvested ?? 1;
                    var harvestedCorn = fieldData.FirstOrDefault(x => x.Type == CornFieldUpgradeType.Machine && x.level == gameData.MachineLevel)?.harvested ?? 20;
                    gameData.CornSeed += harvestedCorn * harvestCount;
                    var seedlingTransform = seedling.transform;
                    
                    var harvestEffect = Instantiate(harvestEffectPrefab, seedlingTransform);
                    Destroy(harvestEffect, 1f);
                    for (int j = 0; j < harvestCount; j++)
                    {
                        // 株の位置調整
                        var pos = seedlingTransform.position;
                        if (harvestCount > 1)
                        {
                            pos += Vector3.right * (j - 1) * harvestedDistance + Vector3.forward * (j - 1);
                        }
                        this.CallWaitForFrame(harvestedFrameInterval * j, () =>
                        {
                            var harvestAnimation = Instantiate(harvestPrefab, pos, Quaternion.identity, harvestSpawnTarget);
                            this.CallWaitForSeconds(.5f, () =>
                            {
                                this.CallLerp(.4f, f =>
                                {
                                    harvestAnimation.transform.position = Vector3.Lerp(pos, harvestInsertPosition.position, f.EaseInQuadratic());
                                }, () =>
                                {
                                    // コーン排出
                                    cornHarvester.AddCount(harvestedCorn);
                                    Destroy(harvestAnimation);
                                });
                            });
                        });
                    }

                    // 新しい苗
                    var newGene = GenerateSeedlingGene(plantLineData.Level);
#if DEVELOPMENT_BUILD || UNITY_EDITOR
                        if (UsayaStorageManager.LoadOrDefault(UsayaStorageFilename.Settings_Data, "DebugFastGrowing", false))
                        {
                            newGene.Period = newGene.Period / 3;
                        }
#endif
                    if (useFertilizer)
                    {
                        newGene.Period = Random.Range(2, 4);
                    }
                    seedling.SetSeedlingGene(newGene.FirstTime, newGene.Period, newGene.Level);
                    progressData.Level = newGene.Level;
                    progressData.Period = newGene.Period;
                    progressData.FirstTime = newGene.FirstTime;
                    GameDataManager.SaveGameData();
                    
                    // チュートリアル時新しい苗を隠す
                    if (gameData.isFirstPlay)
                    {
                        seedling.SetSeedlingGene(DateTime.MaxValue, Int32.MaxValue, newGene.Level);
                    }
                }).AddTo(compositeDisposable);
            }
        }

        // 時短ボタン
        promoteGrowthButton.OnClickAsObservable().Subscribe(_ =>
        {
            VibrationManager.Instance.PlayVibrationOnce();
            foreach (var plantLine in plantLines) 
            {
                if (gameData.PlantLineDataList.FirstOrDefault(data => data.Type == plantLine.LineName) is PlantLineData plantLineData) 
                {
                    for (int i = 0; i < plantLine.Seedlings.Count; i++)
                    {
                        if (Random.Range(0, 2) == 0)
                        {
                            continue;
                        }
                        var progressData = gameData.SeedlingDataList.First(data => data.type == plantLineData.Type).Seedlings[i];
                        var seedling = plantLine.Seedlings[i];
                        progressData.FirstTime = progressData.FirstTime.AddSeconds(-1);
                        seedling.PromoteGrowth(progressData.FirstTime);
                    }
                }
            }

            // 設定のセーブ
            GameDataManager.SaveGameData();
        }).AddTo(compositeDisposable);
        
        // 強化ボタン通知
        var upgradePrice = int.MaxValue;
        if (fieldData.FirstOrDefault(x => x.Type == CornFieldUpgradeType.Machine && x.level == gameData.MachineLevel + 1)?.price is int nextMachinePrice)
        {
            upgradePrice = Mathf.Min(upgradePrice, nextMachinePrice);
        }
        foreach (var plantLine in plantLines)
        {
            var upgradeType = FieldUpgradeData.PlantTypeToUpgradeType(plantLine.LineName);
            var nextRank = CornFieldRank.Rank1;
            if (gameData.PlantLineDataList.FirstOrDefault(data => data.Type == plantLine.LineName) is PlantLineData plantLineData)
            {
                if (plantLineData.Level == CornFieldRank.Rank3)
                {
                    continue;
                }
                nextRank = CornFieldReinforcement.GetNextRank(plantLineData.Level);
            }
            if (fieldData.FirstOrDefault(x => x.Type == upgradeType && x.level == (int) nextRank)?.price is int nextPrice)
            {
                upgradePrice = Mathf.Min(upgradePrice, nextPrice);
            }
        }
        upgradeButtonBadge.SetActive(upgradePrice <= CoinManager.Instance.OwnCoin);
    }

    private IDisposable SetFertilizerTimer(int time)
    {
        return Observable.Timer(TimeSpan.Zero,TimeSpan.FromSeconds(1f))
            .Select(x => (int)(time - x))
            .TakeWhile(x => x > 0)
            .Subscribe(x =>
            {
                fertilizerButtonView.SetTime(x);
            }, () =>
            {
                fertilizerButtonView.SetButtonActive(true);
            });
    }

    private void SetData()
    {
        var gameData = GameDataManager.GameData;
        if (gameData.PlantLineDataList == null || gameData.PlantLineDataList.Count == 0)
        {
            gameData.PlantLineDataList = new List<PlantLineData>
            {
                new PlantLineData(PlantLineType.Center, CornFieldRank.Rank1),
            };
        }
        if (gameData.SeedlingDataList == null || gameData.SeedlingDataList.Count == 0)
        {
            gameData.SeedlingDataList = new List<SeedlingProgressData>();
        }
        if (gameData.MachineLevel == 0)
        {
            gameData.MachineLevel = 1;
        }
        GameDataManager.SaveGameData();
    }

    private SeedlingData GenerateSeedlingGene(CornFieldRank level)
    {
        return new SeedlingData(DateTime.Now, Random.Range(minPeriod, maxPeriod + 1), level);
    }
}
