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

public enum CustomerType
{
    Walker,
    Customer,
    Vip
}

public class CustomerFlow : MonoBehaviour
{
    private IObservable<CustomerType> customerObservable;
    private IObservable<CustomerType> walkerObservable;
    private IObservable<CustomerType> adWalkerObservable;
    private readonly Subject<IObservable<Unit>> adStartObservable = new Subject<IObservable<Unit>>();
    private IObservable<CustomerType> vipCustomerObservable;
    private readonly Subject<IObservable<Unit>> vipCustomerSubject = new Subject<IObservable<Unit>>();
    private IObservable<CustomerType> tastingCustomerObservable;
    private static readonly float CheckHeartInterval = 1f;
    private static readonly float TenMinutes = 60f * 10;
    
    [Header("1分間あたりの歩行者数")]
    [SerializeField] private float walkerInterval = 60f / 6;

    [Header("宣伝時間(秒)")]
    [SerializeField] private float adWalkerDuration = 60f;
    [Header("宣伝で来るお客さんの数")]
    [SerializeField] private int adWalkerCount = 20;

    [Header("VIP宣伝で来るお客さんの数")]
    [SerializeField] private int vipCustomerCount = 6;
    [Header("VIP宣伝で来るお客さん出現間隔(秒)")]
    [SerializeField] private float vipCustomerInterval = 5f;
    
    [Header("試食のお客さん出現間隔(秒)")]
    [SerializeField] private float tastingCustomerInterval = 5f;

    public float TastingCustomerInterval => tastingCustomerInterval;
    private int adActiveCount = 0;
    // bonus
    private int customerBonus;
    private int adWalkerBonus;

    public IObservable<CustomerType> Flow => walkerObservable.Merge(customerObservable, adWalkerObservable, vipCustomerObservable, tastingCustomerObservable);
    
    private void Awake()
    {
        adStartObservable.AddTo(this);
        vipCustomerSubject.AddTo(this);
        
        var shopLevelList = SpreadsheetDataManager.Instance.GetBaseDataList<ShopLevelData>(Const.ShopLevelDataSheet);
        shopLevelList = shopLevelList.Where(data => data.shopLevel != Const.SpecialShopLevel).ToList();
        
        // １秒間隔でハートを確認
        var changeCustomerFlowObservable = Observable.Interval(TimeSpan.FromSeconds(CheckHeartInterval))
            .Select(_ => GameDataManager.GameData.Heart);

        // お客さん出現タイマー
        customerObservable = changeCustomerFlowObservable
            .DistinctUntilChanged()
            .Select(heart => TenMinutes / (shopLevelList.Last(x => x.heart <= heart).customer + customerBonus)) // 10分間期待値を来客の間隔に変換
            .DistinctUntilChanged()
            // .Do(x => Debug.Log($"changeInterval:{x}"))
            .Select(customerInterval => Observable.Interval(TimeSpan.FromSeconds(customerInterval)))
            .Switch()
            // .Do(_ => Debug.Log($"customer:{GetHashCode()}"))
            .Select(_ => CustomerType.Customer);

        // 歩行者出現頻度、立ち止まり確率も設定(歩行者タイマー1分間に6人
        walkerObservable = Observable.Interval(TimeSpan.FromSeconds(walkerInterval))
            // .Do(l => Debug.Log($"walker:{GetHashCode()}"))
            .Select(_ => CustomerType.Walker);

        // 宣伝時、タップすると60秒だけ稼働するストリーム
        adWalkerObservable = adStartObservable
            .Switch()
            // .Do(_ => Debug.Log($"adWalker:{GetHashCode()}"))
            .Select(_ => CustomerType.Walker);
#if DEVELOPMENT_BUILD || UNITY_EDITOR
        if (UsayaStorageManager.LoadOrDefault(UsayaStorageFilename.Settings_Data, "DebugManyWalker", false))
        {
            // Observable.Timer(TimeSpan.FromSeconds(1f), TimeSpan.FromSeconds(70f)).Subscribe(_ => { adStartObservable.OnNext(default); }).AddTo(this);
        }
#endif

        // VIP宣伝
        vipCustomerObservable = vipCustomerSubject
            .Switch()
            .Select(_ => CustomerType.Vip);
        
        // 試食
        // tastingCustomerInterval毎にTastingCountを確認
        var tastingTimer = Observable.Interval(TimeSpan.FromSeconds(tastingCustomerInterval))
            .Where(_ => adActiveCount <= 0) // 宣伝中判定
            .Where(_ => GameDataManager.GameData.ShopStock.Count > 0) // 在庫ゼロ判定
            .Where(_ => GameDataManager.GameData.TastingCount > 0) // 試食残り判定
            .Publish()
            .RefCount();
        // 試食残りカウントを減らす
        tastingTimer.Subscribe(_ =>
        {
            GameDataManager.GameData.TastingCount--;
        });
        tastingCustomerObservable = tastingTimer
            // .Do(_ => Debug.Log($"tastingCustomer remain:{GameDataManager.GameData.TastingCount}"))
            .Select(_ => CustomerType.Customer);
    }

    public void StartAdWalker(Action onComplete = null)
    {
        var timerObservable = AdWalkerTimer().Publish().RefCount();
        adStartObservable.OnNext(timerObservable);
        adActiveCount++;
        timerObservable.Subscribe(_ => { }, () =>
        {
            adActiveCount--;
            onComplete?.Invoke();
        }).AddTo(this);
    }

    private IObservable<Unit> AdWalkerTimer()
    {
        return Observable.Timer(TimeSpan.Zero, TimeSpan.FromSeconds(adWalkerDuration/(adWalkerCount + adWalkerBonus)))
            .Take(TimeSpan.FromSeconds(adWalkerDuration))
            .AsUnitObservable();
    }

    public void StartVip()
    {
        vipCustomerSubject.OnNext(Observable.Timer(TimeSpan.Zero, TimeSpan.FromSeconds(vipCustomerInterval))
            .Take(vipCustomerCount)
            .AsUnitObservable());
    }

    public void UpdateBonus(Dictionary<ShopCustomizeBonusCategory, (int bonusLevel, int value)> bonusList)
    {
        customerBonus = bonusList[ShopCustomizeBonusCategory.Customer].value;
        adWalkerBonus = bonusList[ShopCustomizeBonusCategory.AdWalker].value;
    }
}
