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

public class MarketManager : MonoBehaviour
{
    [SerializeField] private GameObject closeSign;
    [SerializeField] private ShopStockView stockView;
    [SerializeField] private MarketCartView cartView;
    [SerializeField] private BrotherBlueView blueView;
    [SerializeField] private Transform pinkTarget;
    [SerializeField] private Transform coinPrefab;
    [SerializeField] private Transform rootTransform;
    private Market market;
    List<ProductData> productDataList;

    private void Start()
    {
        var gameData = GameDataManager.GameData;
        CoinManager.Instance.ChangeCoin(gameData.Coin);
        HeartMeter.Instance.Initialize();
        HeartMeter.Instance.SetHeart(gameData.Heart);
        
        market = Market.Instance;
        productDataList = SpreadsheetDataManager.Instance.GetBaseDataList<ProductData>(Const.ProductDataSheet);
        stockView.SetStock(gameData.StorageTanks);
        var startStocks = market.ShuffledOrder.Select(x => (x, market.DisplayFlavors[x])).ToList();
        cartView.Initialize();
        cartView.SetStock(startStocks, false);
        BrotherPinkView.Instance.SetBrotherView(pinkTarget);

        // Customerの各アニメーション設定
        foreach (var controller in market.CustomerControllerList)
        {
            GenerateCustomer(controller);
        }
        market.CustomerControllerList.ObserveAdd().Subscribe(x =>
        {
            GenerateCustomer(x.Value);
        }).AddTo(this);

        // 販売
        market.SellObservable.Subscribe(coin =>
        {
            // コイン獲得エフェクト
            CoinEffect(coin);
            CoinManager.Instance.AddCoinWithEffect(coin, () => { });
            
            blueView.SellAction();
        }).AddTo(this);

        market.SellOrderSubject.Subscribe(x =>
        {
            // 販売アニメーション
            foreach (var order in x.orders)
            {
                cartView.SellStock(order);
            };

            // 時間を開けて補充アニメーション
            this.CallWaitForSeconds(1f, () =>
            {
                stockView.SetStock(gameData.StorageTanks);
                if (gameData.ShopStock.Count == Market.ShopStockCount)
                {
                    // 補充したフレーバーのスキンを設定
                    foreach (var order in x.orders)
                    {
                        cartView.Refill(order, market.DisplayFlavors[order]);
                    }
                }
                else if (x.isReorder)
                {
                    // 陳列表示更新(陳列13=650ms,7=350ms)
                    var stocks = market.ShuffledOrder.Select(i => (i, market.DisplayFlavors[i])).ToList();
                    cartView.SetStock(stocks, true);
                }
            });
        }).AddTo(this);

        // 開閉店
        CompositeDisposable shopStateCompositeDisposable = new CompositeDisposable();
        shopStateCompositeDisposable.AddTo(this);
        market.CurrentShopState.Subscribe(state =>
        {
            shopStateCompositeDisposable.Clear();
            switch (state)
            {
                case ShopState.Open:
                    BrotherPinkView.Instance.SetNormal();
                    closeSign.SetActive(false);
                    break;
                case ShopState.Busy:
                    break;
                case ShopState.Close:
                    if (market.CustomerList.Count(x => x.State.Value == CustomerState.Order) == 0)
                    {
                        BrotherPinkView.Instance.SetSleepy();
                        closeSign.SetActive(true);
                    }
                    else
                    {
                        // お客さんがいなくなったあと、閉店の看板を出す
                        Observable.CombineLatest(
                                market.CustomerList
                                    .Select(x => x.State)
                                    .Where(x => x.Value == CustomerState.Order))
                            .FirstOrDefault(states => states.Count(x => x == CustomerState.Order) == 0)
                            .Delay(TimeSpan.FromSeconds(2f))
                            .Subscribe(_ =>
                            {
                                BrotherPinkView.Instance.SetSleepy();
                                closeSign.SetActive(true);
                            }).AddTo(shopStateCompositeDisposable);
                    }
                    break;
                default:
                    throw new ArgumentOutOfRangeException(nameof(state), state, null);
            }
        }).AddTo(this);
    }

    private void CoinEffect(int count)
    {
        var effect = Instantiate(coinPrefab, Vector3.zero, Quaternion.identity, rootTransform);
        effect.GetComponentInChildren<TextMeshProUGUI>().text = count.ToString();
        Destroy(effect.gameObject, 1f);
    }

    private void GenerateCustomer(CustomerController controller)
    {
        var customerObject = new GameObject();
        customerObject.transform.localPosition = controller.transform.localPosition;
        // controllerが破棄のタイミングでこちらも破棄
        controller.OnDestroyAsObservable().Subscribe(_ =>
        {
            Destroy(customerObject);
        }).AddTo(customerObject);
        // customer位置同期
        this.UpdateAsObservable().Subscribe(_ =>
        {
            customerObject.transform.localPosition = controller.transform.localPosition;
        }).AddTo(customerObject);
        
        var customerAnimator = Instantiate(controller.CustomerPrefab, customerObject.transform);
        controller.CurrentMovingType.Subscribe(x =>
        {
            customerAnimator.SetTrigger(x);
        }).AddTo(customerAnimator);
        controller.IsDefaultSide.Subscribe(x =>
        {
            customerAnimator.SetSide(x);
        }).AddTo(customerAnimator);
        controller.WantFlavor
            .SkipLatestValueOnSubscribe()
            .Subscribe(wantData =>
            {
                if (productDataList.FirstOrDefault(data => data.id == wantData.FlavorId)?.GetProductPrefab() is MarketPopcornView prefab)
                {
                    customerAnimator.SetWantFlavor(prefab, wantData.Rarity);
                }
            }).AddTo(customerAnimator);
        controller.IsComplain
            .SkipLatestValueOnSubscribe()
            .Subscribe(active =>
            {
                if (active)
                {
                    customerAnimator.ShowComplain();
                }
            }).AddTo(customerAnimator);
        controller.Purchased.Subscribe(_ =>
        {
            customerAnimator.HideOrderPopup();
            var heartAnimation = customerAnimator.GetComponent<HeartAnimation>();
            heartAnimation.GetHeart(HeartMeter.Instance.transform, () =>
            {
                HeartMeter.Instance.AddHeart(1);
            });
        }).AddTo(customerAnimator);
        var eventTrigger = customerAnimator.gameObject.AddComponent<ObservableEventTrigger>();
        eventTrigger.OnPointerClickAsObservable()
            .Where(_ => market.CurrentShopState.Value != ShopState.Close)
            .Take(1)
            .Subscribe(_ =>
            {
                if (customerAnimator.TryGetComponent(typeof(Collider2D), out var target))
                {
                    Destroy(target);
                }
                if (controller.State.Value == CustomerState.Leave
                    || controller.State.Value == CustomerState.EatingLeave
                    || controller.State.Value == CustomerState.SadLeave)
                {
                    return;
                }
                controller.Tapped();
                customerAnimator.ShowTapReaction();
            }).AddTo(customerAnimator);
    }
}