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

namespace MyGame.Scenes.MiniGame.Scripts
{
    public class ResultManager : MonoBehaviour
    {
        [SerializeField] private GameObject titleObject;
        [SerializeField] private GameObject meterObject;
        [SerializeField] private GameObject detailObject;
        [SerializeField] private Button closeButton;
        [SerializeField] private Button retryButton;
        [SerializeField] private Image meterProgressImage;
        [SerializeField] private TextMeshProUGUI meterProgressText;
        [SerializeField] private Text materialNameText;
        [SerializeField] private Transform materialImage;
        [SerializeField] private Text materialAmountText;
        [SerializeField] private float detailOffset;
        [SerializeField] private float progressDuration = .5f;
        [SerializeField] private float waitButtonActive = .5f;
        [SerializeField] private float waitProgress = .5f;
        private float progressValue;

        public IObservable<Unit> OnRetry => retryButton.OnClickAsObservable().TakeUntilDestroy(this);
        public IObservable<Unit> OnClose => closeButton.OnClickAsObservable().TakeUntilDestroy(this);

        public void ShowResult(int score, ScrollGamePlaceData[] placeList, ScrollGameStageData stageData)
        {
            var gameData = GameDataManager.GameData;
            var shopDataList = SpreadsheetDataManager.Instance.GetBaseDataList<ShopData>(Const.ShopDataSheet);

            if (!(gameData.ScrollGameStageScoreList.FirstOrDefault(data => data.Id == stageData.id) is ScrollGameScoreData stageScoreData))
            {
                stageScoreData = new ScrollGameScoreData
                {
                    Id = stageData.id,
                    Score = 0
                };
                gameData.ScrollGameStageScoreList.Add(stageScoreData);
            }

            if (!(gameData.ScrollGamePlaceScoreList.FirstOrDefault(data => data.Id == placeList[0].id) is ScrollGameScoreData placeScoreData))
            {
                placeScoreData = new ScrollGameScoreData
                {
                    Id = placeList[0].id,
                    Score = 0
                };
                gameData.ScrollGamePlaceScoreList.Add(placeScoreData);
            }
            
            // スコア更新
            stageScoreData.Score = Math.Max(stageScoreData.Score, score);
            var prevPlaceScore = placeScoreData.Score;
            placeScoreData.Score += score;
            
            foreach (var placeData in placeList.Where(data => data.itemId != 0))
            {
                var amount = Mathf.FloorToInt((float)score / placeData.needScore);
                var shopData = shopDataList.FirstOrDefault(data => data.itemId == placeData.itemId);
                materialNameText.text = shopData.Name;
                // materialImage
                materialAmountText.text = $"x{amount}";
                Shopping.AddItem(shopData, amount);
            }

            var recipePlaceData = placeList
                .OrderBy(data => data.needScore)
                // .Where(data => !gameData.MyRecipes.Contains(data.recipeId))
                .FirstOrDefault(data => data.recipeId != 0);
            if (recipePlaceData != null && placeScoreData.Score >= recipePlaceData.needScore)
            {
                if (!gameData.MyRecipes.Contains(recipePlaceData.recipeId))
                {
                    gameData.MyRecipes = new List<int>(gameData.MyRecipes){recipePlaceData.recipeId}.ToArray();
                    gameData.DailyRecipeGetCount++;
                }
            }
            GameDataManager.SaveGameData();
            
            // view
            gameObject.SetActive(true);
            titleObject.SetActive(true);
            detailObject.SetActive(true);
            
            // 商品獲得済みならレシピ非表示
            if (recipePlaceData is null)
            {
                // detailの表示位置変更
                detailObject.transform.SetLocalPositionY(detailOffset);
            }
            else
            {
                meterObject.SetActive(true);
                SetProgress((float)prevPlaceScore / recipePlaceData.needScore, false);
                this.CallWaitForSeconds(waitProgress, () =>
                {
                    SetProgress((float)placeScoreData.Score / recipePlaceData.needScore);
                });
            }
            this.CallWaitForSeconds(waitButtonActive, () =>
            {
                closeButton.gameObject.SetActive(true);
                retryButton.gameObject.SetActive(true);
            });
        }

        public void Reset()
        {
            gameObject.SetActive(false);
            titleObject.SetActive(false);
            meterObject.SetActive(false);
            detailObject.SetActive(false);
            closeButton.gameObject.SetActive(false);
            retryButton.gameObject.SetActive(false);
            progressValue = 0f;
        }

        private void SetProgress(float newValue, bool animated = true, Action onComplete = null)
        {
            var prevValue = progressValue;
            newValue = Mathf.Clamp01(newValue);
            progressValue = newValue;
            this.CallLerp(animated ? progressDuration : 0f, f =>
            {
                var value = Mathf.Lerp(prevValue, newValue, f.EaseOutQuadratic());
                meterProgressText.text = $"{value * 100:0}%";
                meterProgressImage.fillAmount = value;
            }, () => onComplete?.Invoke());
        }
    }
}