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

public class GameDataObserver : SingletonMonoBehaviour<GameDataObserver>
{
    [SerializeField] private FloatReactiveProperty checkInterval = new FloatReactiveProperty(.1f);
    private IObservable<int> heartObserver;
    public IObservable<int> Heart => heartObserver;

    private IObservable<int> sceneCounter;
    public IObservable<int> SceneCounter => sceneCounter;
    
    public IObservable<bool> ShopLevelUpdate;

    private void Start()
    {
        checkInterval.AddTo(this);
        var gameData = GameDataManager.GameData;
        var levelList = SpreadsheetDataManager.Instance.GetBaseDataList<ShopLevelData>(Const.ShopLevelDataSheet);
        heartObserver = checkInterval
            .Select(x =>
                Observable.Interval(TimeSpan.FromSeconds(x))
                    .Select(_ => gameData.Heart)
                    .DistinctUntilChanged())
            .Switch();
        
        var shopLevelObserver = checkInterval
            .Select(x =>
                Observable.Interval(TimeSpan.FromSeconds(x))
                    .Select(_ => gameData.ViewedShopLevel)
                    .DistinctUntilChanged())
            .Switch();

        sceneCounter = checkInterval
            .Select(x =>
                Observable.Interval(TimeSpan.FromSeconds(x))
                    .Select(_ => UnityEngine.SceneManagement.SceneManager.sceneCount)
                    .DistinctUntilChanged()
                    .Delay(TimeSpan.FromSeconds(.4f))
                    // .Do(c => { Debug.Log($"sceneCount:{c}");})
                )
            .Switch();
        
        ShopLevelUpdate = Observable.CombineLatest(heartObserver, shopLevelObserver, sceneCounter,
            (heart, level, sceneCount) =>
            {
                var currentLevel = levelList.LastOrDefault(data => data.heart <= heart)?.shopLevel ?? 1;
                return currentLevel > level && sceneCount == 1;
            })
            .DistinctUntilChanged()
            .Publish(false)
            .RefCount();
#if UNITY_EDITOR
        // ShopLevelUpdate.Subscribe(x => { Debug.Log($"change:{x}"); });
#endif
        // デイリーミッション日付チェック
        sceneCounter
            .Where(x => x <= 1)
            .Subscribe(x =>
            {
                if (gameData.ViewedShopLevel == 0)
                {
                    return;
                }

                var lastSetDateUtc = DateTime.FromBinary(gameData.lastDailyMissionSetTime);
                // 現時刻が最後にデイリーミッションを設定した日より前の場合無視(時間操作対策)
                if (lastSetDateUtc > DateTime.UtcNow)
                {
#if UNITY_EDITOR
                    Debug.Log($"不正な時刻 {lastSetDateUtc:s}");
#endif
                    return;
                }

                // ミッションリセットチェック(0時)
                if (gameData.GetDailyMissionLimitTime().TotalSeconds > 0)
                {
                    return;
                }
#if UNITY_EDITOR
                Debug.Log($"reset daily mission");
#endif
                // ミッション実績リセット
                gameData.dailyMissionAchievedIdArray = new int[0];
                gameData.dailyMissionCompleted = false;
                gameData.ResetDailyTotalCount();
                // 新ミッション登録
                var missionList = SpreadsheetDataManager.Instance.GetBaseDataList<MissionData>(Const.MissionDataSheet);
                var targetList = missionList.Where(data =>
                    data.Category == MissionCategory.Daily && data.shopLevel <= gameData.ViewedShopLevel);
                gameData.dailyMissionIdArray = targetList.ToList().RandomChoose(3).Select(data => data.id).ToArray();
#if UNITY_EDITOR
                gameData.dailyMissionIdArray = new List<int>(gameData.dailyMissionIdArray){291}.ToArray();
#endif
                gameData.lastDailyMissionSetTime = DateTime.UtcNow.ToBinary();
                gameData.dailyLoginCount++;
                GameDataManager.SaveGameData();
            });
    }
}
