using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.Linq;
using Save;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
using YG;
using static UnityEngine.Random;

public class UserData
{
    public bool IsAuthorized { get; set; }
    public int Score { get; set; }
    public int TotalDorams { get; set; }
    public int CorrectAnswers { get; set; }
    public int WrongAnswers { get; set; }
    public List<int> ShownDoramasIndexes { get; set; } = new();

    public static explicit operator UserData(SavesYG savesYg)
    {
        return new UserData
        {
            Score = savesYg.score,
            TotalDorams = savesYg.totalDorams,
            CorrectAnswers = savesYg.correctAnswers,
            WrongAnswers = savesYg.wrongAnswers,
            ShownDoramasIndexes = savesYg.shownDoramasIndexes,
        };
    }
}

public class GuessDorama : MonoBehaviour
{
    [Header("Default")] public Image image;
    public Button[] buttons;
    public Settings[] settings;
    public SettingsTest[] gayTest;

    // [Header("Sprites")] public Sprite trueAnswer;
    // public Sprite falseAnswer;
    // public Sprite defaultSprite;

    [Header("Texts")] public Text titleText;
    public Text kimchiText;
    public Text rankText;
    public Text nextRankText;
    public Text timer;

    [Header("Rank")] public List<RankSettings> rank;

    [Header("Other")] public GameObject smallObjectPrefab;
    public Transform targetPosition;
    public float speed = 5f;
    public Animator kimchiAnim;
    public GameObject showAdPanel;

    private int _currentDoramaIndex;
    private int _currentScore;
    private int _previousScore;
    private int _correctAnswers;
    private const int RequiredConsecutiveCorrectAnswers = 3;
    private const int DefaultScoreIncrement = 2;
    private const int ConsecutiveCorrectScoreMultiplier = 2;

    private GameManager _gameManager;
    private Canvas _canvas;
    private Leaders _leaders;

    public UserData UserData = new();
    private static readonly int Kimchi = Animator.StringToHash("kimchi");
    private static readonly int KimchiEnd = Animator.StringToHash("kimchi-end");

    [NonSerialized] public bool IsRewardAdsAvailable;
    private bool _isAdsCooldown;
    private bool _isCorrectAnswer;
    private bool _isHandlingInput = false; 

    private void Awake()
    {
        _gameManager = GetComponent<GameManager>();
        _leaders = GetComponent<Leaders>();
        _canvas = FindFirstObjectByType<Canvas>();
    }

    private void Start()
    {
        _currentScore = UserData.Score;
        _previousScore = UserData.Score;

        kimchiText.text = $"{_currentScore}";

        var rankWithDorams = GetRankWithDoramsToNext();
        rankText.text = $"{rankWithDorams.currentRank}";
        nextRankText.text = $"{rankWithDorams.doramsToNextRank}";

        StartCoroutine(UpdateScoreText());
    }

    private IEnumerator UpdateScoreText()
    {
        while (true)
        {
            var targetScore = UserData.Score;

            if (_previousScore != targetScore)
            {
                yield return new WaitForSeconds(0.5f);

                if (_isCorrectAnswer)
                {
                    _currentScore++;
                    StartCoroutine(MoveSmallObject());
                }
                else
                {
                    if (_currentScore < targetScore)
                    {
                        _currentScore++;
                    }
                    else
                    {
                        _currentScore--;
                    }
                }

                kimchiText.text = $"{_currentScore}";

                _previousScore = _currentScore;
                
                kimchiAnim.enabled = true;
                yield return new WaitForSeconds(0.1f);
            }
            else
            {
                if (GameObject.FindWithTag("Kimchi") == null && kimchiAnim.enabled)
                {
                    kimchiAnim.SetTrigger(KimchiEnd);
                    kimchiAnim.enabled = false;
                }

                yield return null;
            }
        }
        // ReSharper disable once IteratorNeverReturns
    }

    private IEnumerator MoveSmallObject()
    {
        var mousePosition = Input.mousePosition;
        mousePosition.z = 10f;
        var worldPosition = Camera.main!.ScreenToWorldPoint(mousePosition);

        var smallObject = Instantiate(smallObjectPrefab, worldPosition, Quaternion.identity, _canvas.transform);
        
        var rectTransform = smallObject.GetComponent<RectTransform>();
        var startPosition = rectTransform.anchoredPosition;
        var endPosition = targetPosition.GetComponent<RectTransform>().anchoredPosition;
        var distance = Vector2.Distance(startPosition, endPosition);
        var startTime = Time.time;

        var continueMoving = true;

        while (continueMoving)
        {
            var journeyLength = (Time.time - startTime) * speed;
            var fracJourney = journeyLength / distance;
            rectTransform.anchoredPosition = Vector2.Lerp(startPosition, endPosition, fracJourney);

            if (fracJourney >= 1f)
            {
                continueMoving = false;

                kimchiAnim.SetTrigger(Kimchi);
            }

            yield return null;
        }

        kimchiAnim.SetTrigger(KimchiEnd);
        Destroy(smallObject);
    }
    
    public void DisableWrongButton()
    {
        var correctAnswer = settings[_currentDoramaIndex].answer[0];

        foreach (var button in buttons.Where(b => b.interactable))
        {
            var buttonText = button.GetComponentInChildren<Text>().text;
            if (buttonText != correctAnswer)
            {
                button.interactable = false;
                break;
            }
        }
    }

    public void OnClickAnswer(Button button)
    {
        if (_isHandlingInput)
            return;
        
        var selectedAnswer = button.GetComponentInChildren<Text>().text;
        var correctAnswer = settings[_currentDoramaIndex].answer[0];

        var img = button.image;
        if (selectedAnswer == correctAnswer)
            HandleCorrectAnswer(img);
        else
            HandleWrongAnswer(button, img);
        
        _isHandlingInput = true;
        StartCoroutine(HandleButtonClick());

        SaveSystem.Save(UserData);
        _leaders.AddToLeaderboard();
    }

    private IEnumerator HandleButtonClick()
    {
        yield return new WaitForSeconds(0.5f);
        _isHandlingInput = false;
    }

    public void UpdateRewardAdsAvailability()
    {
        var answer1 = settings[_currentDoramaIndex].answer[0];
        var remainingWrongButtons =
            buttons.Count(b => b.interactable && b.GetComponentInChildren<Text>().text != answer1);
        var isWrongButtonRemaining = remainingWrongButtons > 0;

        var isCorrectButtonRemaining =
            buttons.Any(b => b.interactable && b.GetComponentInChildren<Text>().text == answer1);

        IsRewardAdsAvailable = isWrongButtonRemaining && isCorrectButtonRemaining;
    }

    private void HandleCorrectAnswer(Image img)
    {
        _isCorrectAnswer = true;
        IsRewardAdsAvailable = false;
        UserData.ShownDoramasIndexes.Add(_currentDoramaIndex);

        _correctAnswers++;
        UserData.CorrectAnswers++;
        UserData.TotalDorams++;

        img.color = new Color(0, 255, 0);
        //img.sprite = trueAnswer;

        ChangeText("Правильно!", new Color(0, 255, 0));

        if (_correctAnswers % RequiredConsecutiveCorrectAnswers == 0)
            UserData.Score += DefaultScoreIncrement * ConsecutiveCorrectScoreMultiplier;
        else
            UserData.Score += DefaultScoreIncrement;

        foreach (var btn in buttons)
        {
            btn.interactable = false;
        }
         
        if (!_isAdsCooldown && _gameManager.IsTryAdValid)
            Ads.TryShowFullScreenAd(Range(0, 20), () => StartCoroutine(Ads.ShowFullscreenAd(showAdPanel, timer)));
        
        if (UserData.TotalDorams >= settings.Length)
        {
            _gameManager.OutGame();
            return;
        }

        StartCoroutine(OnClickStartGame(3));
        StartCoroutine(AdsCooldown());
    }

    private IEnumerator AdsCooldown()
    {
        _isAdsCooldown = true;
        yield return new WaitForSeconds(20);
        _isAdsCooldown = false;
    }

    private void HandleWrongAnswer(Button button, Image img)
    {
        _isCorrectAnswer = false;
        _correctAnswers = 0;
        UserData.WrongAnswers++;

        button.interactable = false;
        img.color = new Color(255, 0, 0);
        //img.sprite = falseAnswer;

        ChangeText("Неправильно!", new Color(255, 0, 0));
        StartCoroutine(ResetText(1));

        UserData.Score -= DefaultScoreIncrement;

        if (UserData.Score < 0)
            UserData.Score = 0;
    }

    private IEnumerator ResetText(int second)
    {
        yield return new WaitForSeconds(second);
        ChangeText("Как называется эта дорама?", new Color(255, 255, 255));
    }

    private void ChangeText(string text, Color color)
    {
        titleText.text = text;
        titleText.color = color;
    }

    public IEnumerator OnClickStartGame(int second)
    {
        yield return new WaitForSeconds(second);
        
        IsRewardAdsAvailable = true;
        ChangeText("Как называется эта дорама?", new Color(255, 255, 255));

        buttons = buttons.OrderBy(_ => value).ToArray();
  
        var nextDoramaIndex = GetNextDoramaIndex();
 
        _currentDoramaIndex = nextDoramaIndex;

        Addressables.LoadAssetAsync<Sprite>(settings[nextDoramaIndex].path).Completed += OnImageLoaded;
        
        //image.sprite = settings[nextDoramaIndex].sprite;

        for (var i = 0; i < buttons.Length; i++)
        {
            var button = buttons[i];

            button.interactable = true;

            button.image.color = new Color(255, 255, 255);
            //button.image.sprite = defaultSprite;

            button.GetComponentInChildren<Text>().text = settings[nextDoramaIndex].answer[i];

            //var animator = button.GetComponentInChildren<Animator>();
        }
    }

    private void OnImageLoaded(AsyncOperationHandle<Sprite> handle)
    {
        if (handle.Status == AsyncOperationStatus.Succeeded)
        {
            var texture = handle.Result;
            image.sprite = texture;
        }
        else
        {
            Debug.LogError("Failed to load the image");
            StartCoroutine(OnClickStartGame(3));
        }
    }

    private int GetNextDoramaIndex()
    {
        var availableIndexes = Enumerable.Range(0, settings.Length).Except(UserData.ShownDoramasIndexes).ToList();

        if (availableIndexes.Count == 0)
        {
            UserData.ShownDoramasIndexes.Clear();
            availableIndexes = Enumerable.Range(0, settings.Length).ToList();
        }

        var randomIndex = Range(0, availableIndexes.Count);
        return availableIndexes[randomIndex];
    }

    public (string currentRank, int doramsToNextRank) GetRankWithDoramsToNext()
    {
        var currentRank = "Ранг не определен";
        var doramsToNextRank = -1;

        for (var i = 0; i < rank.Count; i++)
        {
            var rankSetting = rank[i];
            if (UserData.TotalDorams < rankSetting.dorams)
            {
                break;
            }

            currentRank = rankSetting.name;

            if (i < rank.Count - 1)
            {
                var nextRankSetting = rank[i + 1];
                doramsToNextRank = nextRankSetting.dorams - UserData.TotalDorams;
            }
            else
            {
                doramsToNextRank = 0;
            }
        }

        return (currentRank, doramsToNextRank);
    }
}

[Serializable]
public class Settings
{
    public string path;
    public Sprite sprite;
    public string[] answer = new string[3];
}

[Serializable]
public class SettingsTest
{
    public Sprite sprite;
    public string[] answer = new string[3];
}

[Serializable]
public class RankSettings
{
    public string name;
    public int dorams;
}

если я например нажму очень быстро на кнопки, у меня будет по кд прибавлятся в методе 

private IEnumerator UpdateScoreText()
    {
        while (true)
        {
            var targetScore = UserData.Score;

            if (_previousScore != targetScore)
            {
                yield return new WaitForSeconds(0.5f);

                if (_isCorrectAnswer)
                {
                    _currentScore++;
                    StartCoroutine(MoveSmallObject());
                }
                else
                {
                    if (_currentScore < targetScore)
                    {
                        _currentScore++;
                    }
                    else
                    {
                        _currentScore--;
                    }
                }

                kimchiText.text = $"{_currentScore}";

                _previousScore = _currentScore;
                
                kimchiAnim.enabled = true;
                yield return new WaitForSeconds(0.1f);
            }
            else
            {
                if (GameObject.FindWithTag("Kimchi") == null && kimchiAnim.enabled)
                {
                    kimchiAnim.SetTrigger(KimchiEnd);
                    kimchiAnim.enabled = false;
                }

                yield return null;
            }
        }
        // ReSharper disable once IteratorNeverReturns
    }

оно прибавляет мне только визуальны очки, по этому очки не багаются, но багается визуал, и это плохо. Как исправить это?