using System;
using System.Collections.Generic;
using System.Linq;
using MyGame.Scenes.Main.Scripts;
using TMPro;
using UniRx;
using UniRx.Triggers;
using UnityEngine;
using UnityEngine.UI;

public class HeartMeter : SingletonMonoBehaviour<HeartMeter>
{
    [SerializeField] private Slider slider;
    [SerializeField] private TextMeshProUGUI heartLevel;
    [SerializeField] private GameObject maxObject;
    [SerializeField] private float duration = .5f;
    [Space]
    [SerializeField] private BulkOrderAchievedEffect bulkOrderAchievedEffect;

    private Coroutine coroutine;
    private List<ShopLevelData> shopLevelList = new List<ShopLevelData>();
    private int currentHeartCount;
    private int maxLevel;
    private readonly CompositeDisposable compositeDisposable = new CompositeDisposable();
    private readonly ReactiveProperty<float> viewHeartCount = new ReactiveProperty<float>();
    private readonly ReactiveProperty<int> shopLevel = new ReactiveProperty<int>();
    private readonly ReactiveProperty<bool> fulledHeart = new ReactiveProperty<bool>();
    public IObservable<bool> FulledHeart => fulledHeart.DistinctUntilChanged()
        .CombineLatest(GameDataObserver.Instance.SceneCounter, (fulled, count) => count == 1 && fulled)
        .Where(x => x && UnityEngine.SceneManagement.SceneManager.sceneCount == 1); // シーン数をもう一度チェック

    private float minHeart;
    private float maxHeart;
    
    private void Awake()
    {
        if (CheckInstance()) return;
    }

    private void Start()
    {
        shopLevel.AddTo(this);
        viewHeartCount.AddTo(this);
        fulledHeart.AddTo(this);
        compositeDisposable.AddTo(this);
#if UNITY_EDITOR
        fulledHeart.Subscribe(x => { Debug.Log($"fulled:{x}"); });
#endif
    }

    public void Initialize(int newShopLevel = 0, int newHeartCount = 0)
    {
        compositeDisposable.Clear();
        shopLevelList = SpreadsheetDataManager.Instance.GetBaseDataList<ShopLevelData>(Const.ShopLevelDataSheet);
        shopLevelList = shopLevelList.Where(data => data.shopLevel != Const.SpecialShopLevel).ToList();
        maxLevel = shopLevelList.Last().shopLevel;

        viewHeartCount.SkipLatestValueOnSubscribe().Subscribe(heartCount =>
        {
            if (shopLevel.Value == maxLevel)
            {
                slider.value = 1;
            }
            else
            {
                slider.value = Mathf.InverseLerp(minHeart, maxHeart, heartCount);
            }
        }).AddTo(compositeDisposable);
        SetHeart(newHeartCount);
        SetShopLevel(newShopLevel);
    }
    
    private void SetHeart(int heartCount)
    {
        currentHeartCount = heartCount;
        viewHeartCount.SetValueAndForceNotify(heartCount);
    }

    public void SetShopLevel(int newShopLevel, bool animate = false)
    {
        var level = Mathf.Min(newShopLevel, maxLevel);
        var isMax = level == maxLevel;
        maxObject.SetActive(isMax);
        heartLevel.gameObject.SetActive(!isMax);
        shopLevel.Value = level;
        heartLevel.text = $"{level}";
        minHeart = shopLevelList.FirstOrDefault(data => data.shopLevel == level)?.heart ?? 0;
        maxHeart = shopLevelList.FirstOrDefault(data => data.shopLevel == level + 1)?.heart ?? minHeart;
        if (animate)
        {
            fulledHeart.Value = false;
            var tmpCount = currentHeartCount - (int)minHeart;
            SetHeart((int)minHeart);
            AddHeart(tmpCount);
        }
        else
        {
            viewHeartCount.SetValueAndForceNotify(currentHeartCount);
            fulledHeart.Value = currentHeartCount >= maxHeart && shopLevel.Value < maxLevel;
        }
    }
    public void AddHeart(int value)
    {
        this.SafeStopCoroutine(coroutine);
        currentHeartCount += value;
        coroutine = this.CallWaitForSeconds(duration, () =>
        {
            SetHeart(currentHeartCount);
        });
        var fixValue = Mathf.Min(value, maxHeart);
        this.UpdateAsObservable()
            .Select(_ => Time.deltaTime / duration)
            .Take(TimeSpan.FromSeconds(duration))
            .Subscribe(t =>
            {
                viewHeartCount.Value += fixValue * t;
            }, () =>
            {
                fulledHeart.Value = currentHeartCount >= maxHeart && shopLevel.Value < maxLevel;
            }).AddTo(this);
    }

    public void AddHeartForBulkOrder(Vector3 beginPos, Action onComplete = null)
    {
        bulkOrderAchievedEffect.PlayHeartEffect(beginPos, transform.position, onComplete);
    }
}