using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using DG.Tweening;

namespace com.al_arcade.cs
{
    using shared;

    public enum CsGameState
    {
        Idle, Loading, ShowingSentence, WaitingForWordClick,
        WaitingForDrop, Feedback, Complete
    }

    public class CsGameManager : MonoBehaviour
    {
        public static CsGameManager Instance { get; private set; }

        [Header("Settings")]
        [SerializeField] private float sentenceShowDelay = 0.5f;
        [SerializeField] private float feedbackDuration = 1.5f;
        [SerializeField] private float wordClickCooldown = 0.3f;

        [Header("References")]
        public CsBotController bot;
        public CsUIManager uiManager;
        public Transform wordContainer;


        private CsGameState _state = CsGameState.Idle;
        private CsQuestion[] _questions;
        private int _currentIndex;
        private int _score, _streak, _correctCount, _wrongCount, _wrongClicks;

        private List<CsWordButton> _wordButtons = new();
        private CsWordButton _wrongWordButton;
        private bool _wordClickLocked;

        [Header("Events")]
        public UnityEvent onGameStart;
        public UnityEvent<bool> onAnswerGiven;
        public UnityEvent<int> onGameComplete;

        private Action<bool> _onOptionDropped;

        private void Awake()
        {
            if (Instance != null && Instance != this) { Destroy(gameObject); return; }
            Instance = this;
        }


        public void StartGame() => StartCoroutine(StartGameRoutine());

        public void StartWithQuestions(CsQuestion[] questions)
        {
            _questions = questions;
            BeginGameplay();
        }

        public void ResetGame()
        {
            StopAllCoroutines();
            _state = CsGameState.Idle;
            _currentIndex = _score = _streak = _correctCount = _wrongCount = 0;
            ClearWordButtons();
            if (uiManager != null) uiManager.ResetUI();
            if (bot != null) bot.ResetBot();
        }

        public void OnWordClicked(CsWordButton wordButton)
        {
            if (_state != CsGameState.WaitingForWordClick) return;
            if (_wordClickLocked) return;

            if (wordButton.IsWrong)
            {
                _wrongWordButton = wordButton;
                wordButton.Highlight(true);

                var audio = SSAudioManager.Instance;
                if (audio != null) audio.PlayClickBeep();

                var particles = SSParticleManager.Instance;
                if (particles != null)
                    particles.PlaySparks(wordButton.transform.position, SSColorPalette.Accent);

                _state = CsGameState.WaitingForDrop;
                ShowOptions();
            }
            else
            {
                _wrongClicks++;
                _wordClickLocked = true;
                wordButton.ShakeWrong();

                var audio = SSAudioManager.Instance;
                if (audio != null) audio.PlayWrongBeep();

                StartCoroutine(UnlockAfterCooldown());
            }
        }

        public void OnOptionDropped(bool isCorrectOption)
        {
            _onOptionDropped?.Invoke(isCorrectOption);
        }


        private IEnumerator StartGameRoutine()
        {
            _state = CsGameState.Loading;
            if (uiManager != null) uiManager.ShowLoading("جاري تحميل الأسئلة...");

            var session = SSGameSession.EnsureInstance();
            var api = SSApiManager.EnsureInstance();
            string error = null;

            yield return api.FetchCs(
                session.buildType, session.classCode,
                session.questionCount, session.gradeId,
                qs => _questions = qs,
                err => error = err);

            if (error != null || _questions == null || _questions.Length == 0)
            {
                if (uiManager != null) uiManager.ShowError(error ?? "لا توجد أسئلة");
                _state = CsGameState.Idle;
                yield break;
            }

            if (uiManager != null) uiManager.HideLoading();
            BeginGameplay();
        }

        private void BeginGameplay()
        {
            _currentIndex = _score = _streak = _correctCount = _wrongCount = 0;

            if (uiManager != null)
            {
                uiManager.ShowGameUI();
                uiManager.SetScore(0);
                uiManager.SetProgress(0, _questions.Length);
            }

            onGameStart?.Invoke();
            StartCoroutine(QuestionLoop());
        }

        private IEnumerator QuestionLoop()
        {
            while (_currentIndex < _questions.Length)
            {
                yield return PresentQuestion(_questions[_currentIndex]);
                _currentIndex++;
                if (uiManager != null)
                    uiManager.SetProgress(_currentIndex, _questions.Length);
            }

            _state = CsGameState.Complete;
            yield return VictorySequence();
        }

        private IEnumerator PresentQuestion(CsQuestion question)
        {
            _state = CsGameState.ShowingSentence;
            _wrongClicks = 0;
            _wrongWordButton = null;

            if (bot != null) bot.ShowSpeechBubble();

            ClearWordButtons();
            yield return new WaitForSeconds(sentenceShowDelay);

            SpawnWords(question);
            yield return new WaitForSeconds(0.3f);

            _state = CsGameState.WaitingForWordClick;
            if (uiManager != null)
                uiManager.ShowHint("انقر على الكلمة الخاطئة في الجملة");

            bool questionComplete = false;
            _onOptionDropped = null;

            while (!questionComplete)
            {
                if (_state == CsGameState.WaitingForDrop)
                {
                    bool? result = null;
                    _onOptionDropped = correct => result = correct;

                    while (result == null) yield return null;

                    if (result == true)
                    {
                        questionComplete = true;
                        yield return CorrectAnswerFeedback(question);
                    }
                    else
                    {
                        yield return WrongOptionFeedback();
                    }
                }
                else
                {
                    yield return null;
                }
            }

            if (uiManager != null) uiManager.HideOptions();
            yield return new WaitForSeconds(0.5f);
        }

        private IEnumerator CorrectAnswerFeedback(CsQuestion question)
        {
            _state = CsGameState.Feedback;
            _correctCount++;
            _streak++;

            int points = Mathf.Max(100 - _wrongClicks * 15, 25);
            if (_streak >= 3) points += (_streak - 2) * 25;
            _score += points;

            if (_wrongWordButton != null)
                _wrongWordButton.ReplaceText(question.correct_answer);

            if (uiManager != null)
            {
                uiManager.ShowFeedback($"ممتاز! +{points} ✓", true);
                uiManager.SetScore(_score);
                uiManager.SetStreak(_streak);
            }

            if (bot != null) bot.PlayHappy();

            var audio = SSAudioManager.Instance;
            if (audio != null)
            { if (audio.sfxCorrect != null) audio.PlayCorrect(); else audio.PlayCorrectBeep(); }

            var particles = SSParticleManager.Instance;
            if (particles != null && _wrongWordButton != null)
                particles.PlayCorrectBurst(_wrongWordButton.transform.position);

            onAnswerGiven?.Invoke(true);
            yield return new WaitForSeconds(feedbackDuration);
        }

        private IEnumerator WrongOptionFeedback()
        {
            _wrongClicks++;

            if (uiManager != null)
                uiManager.ShowFeedback("حاول مرة أخرى ✗", false);

            if (bot != null) bot.PlaySad();

            var audio = SSAudioManager.Instance;
            if (audio != null) audio.PlayWrongBeep();

            if (Camera.main != null)
            {
                DOTween.Kill(Camera.main.transform, "csShake");
                Camera.main.transform.DOShakePosition(0.3f, 0.15f, 10)
                    .SetId("csShake");
            }

            yield return new WaitForSeconds(0.8f);
        }


        private void SpawnWords(CsQuestion question)
        {
            if (question.words == null || question.words.Length == 0) return;
            ClearWordButtons();

            int wordCount = question.words.Length;


            float padding = 0.6f;
            float gapBetween = 0.25f;
            float charWidth = 0.32f;

            float[] wordWidths = new float[wordCount];
            float totalWidth = 0;
            for (int i = 0; i < wordCount; i++)
            {
                float w = question.words[i].word_text.Length * charWidth + padding;
                w = Mathf.Max(w, 1.0f);
                wordWidths[i] = w;
                totalWidth += w;
            }
            totalWidth += (wordCount - 1) * gapBetween;


            float maxAllowedWidth = 14f;
            float scaleFactor = 1f;
            if (totalWidth > maxAllowedWidth)
            {
                scaleFactor = maxAllowedWidth / totalWidth;
                totalWidth = maxAllowedWidth;
                for (int i = 0; i < wordCount; i++)
                    wordWidths[i] *= scaleFactor;
            }


            Vector3 basePos = bot != null
                ? bot.transform.position + Vector3.up * 3.5f
                : Vector3.up * 4f;


            float startX = totalWidth / 2f;
            float currentX = startX;

            for (int i = 0; i < wordCount; i++)
            {
                var word = question.words[i];
                float halfW = wordWidths[i] / 2f;
                float posX = currentX - halfW;

                var wordObj = new GameObject($"Word_{i}_{word.word_text}");
                if (wordContainer != null)
                    wordObj.transform.SetParent(wordContainer);
                wordObj.transform.position = basePos + Vector3.right * posX;

                var wb = wordObj.AddComponent<CsWordButton>();
                wb.Setup(word.word_text, word.is_wrong, i, wordWidths[i], scaleFactor);
                _wordButtons.Add(wb);


                wordObj.transform.localScale = Vector3.zero;
                wordObj.transform.DOScale(Vector3.one, 0.4f)
                    .SetDelay(i * 0.08f)
                    .SetEase(Ease.OutBack);

                currentX -= wordWidths[i] + gapBetween;
            }
        }

        private void ShowOptions()
        {
            var question = _questions[_currentIndex];
            if (uiManager != null)
            {
                uiManager.ShowOptions(question.options, _wrongWordButton);
                uiManager.ShowHint("اسحب الإجابة الصحيحة إلى الكلمة الخاطئة");
            }
        }

        private void ClearWordButtons()
        {
            foreach (var wb in _wordButtons)
            {
                if (wb != null && wb.gameObject != null)
                {
                    DOTween.Kill(wb.transform);
                    Destroy(wb.gameObject);
                }
            }
            _wordButtons.Clear();
        }

        private IEnumerator UnlockAfterCooldown()
        {
            yield return new WaitForSeconds(wordClickCooldown);
            _wordClickLocked = false;
        }


        private IEnumerator VictorySequence()
        {
            var audio = SSAudioManager.Instance;
            if (audio != null)
            { if (audio.sfxVictory != null) audio.PlayVictory(); else audio.PlaySuccessJingle(); }

            var particles = SSParticleManager.Instance;
            if (particles != null) particles.PlayScreenConfetti();

            if (bot != null) bot.PlayVictoryDance();

            yield return new WaitForSeconds(1f);

            if (uiManager != null)
                uiManager.ShowResults(_score, _correctCount, _wrongCount,
                    _questions.Length, _streak);

            onGameComplete?.Invoke(_score);
        }

        public int Score => _score;
    }
}
