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

namespace com.al_arcade.mcq
{
    using shared;

    public enum McqGameState
    {
        Idle, Loading, ShowingQuestion, WaitingForAnswer,
        AnswerFeedback, BetweenQuestions, GameComplete, GameOver
    }

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

        [Header("Game Settings")]
        [SerializeField] private float gateSpawnDistance = 50f;
        [SerializeField] private float questionDisplayTime = 1.5f;
        [SerializeField] private float feedbackDisplayTime = 2f;
        [SerializeField] private float playerRunSpeed = 12f;
        [SerializeField] private float gateSpacing = 4f;
        [SerializeField] private float streakBonusThreshold = 3;
        [SerializeField] private int totalLives = 5;

        [Header("References")]
        public McqPlayerRunner player;
        public McqCompetitor competitor;
        public McqQuestionDisplay questionDisplay;
        public McqUIManager uiManager;
        public Transform gateParent;
        public McqPrefabBuilder prefabBuilder;

        [Header("Runtime State (Read Only)")]
        [SerializeField] private McqGameState _state = McqGameState.Idle;
        public McqGameState State => _state;

        private McqQuestion[] _questions;
        private int _currentIndex;
        private int _score, _streak, _bestStreak, _lives;
        private int _correctCount, _wrongCount;

        private List<McqGateController> _activeGates = new();
        private int _correctGateIndex = -1;

        [Header("Events")]
        public UnityEvent onGameStart;
        public UnityEvent<McqQuestion> onQuestionPresented;
        public UnityEvent<bool> onAnswerGiven = new UnityEvent<bool>();
        public UnityEvent<int, int> onScoreChanged;
        public UnityEvent<int> onLifeLost;
        public UnityEvent<int> onGameComplete;
        public UnityEvent onGameOver = new UnityEvent();

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


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

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

        public void ResetGame()
        {
            StopAllCoroutines();
            _state = McqGameState.Idle;
            _currentIndex = 0;
            _score = _streak = _bestStreak = _correctCount = _wrongCount = 0;
            _lives = totalLives;
            _questions = null;

            foreach (var g in _activeGates)
                if (g != null) { DOTween.Kill(g.transform); Destroy(g.gameObject); }
            _activeGates.Clear();

            if (player != null) player.ResetToStart();
            if (uiManager != null) uiManager.ResetUI();
            if (questionDisplay != null) questionDisplay.Hide();
        }


        private IEnumerator StartGameRoutine()
        {

            player?.SetupManager(this);
            competitor?.SetupManager(this);

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

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

            yield return api.FetchMcq(
                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 = McqGameState.Idle;
                yield break;
            }

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

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

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

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

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

            if (_lives <= 0)
            {
                _state = McqGameState.GameOver;
                yield return GameOverSequence();
            }
            else
            {
                _state = McqGameState.GameComplete;
                yield return VictorySequence();
            }
        }

        private IEnumerator PresentQuestion(McqQuestion question)
        {
            _state = McqGameState.ShowingQuestion;

            if (questionDisplay != null)
                questionDisplay.Show(question.question_text, question.source);

            onQuestionPresented?.Invoke(question);
            yield return new WaitForSeconds(questionDisplayTime);

            _state = McqGameState.WaitingForAnswer;
            SpawnGates(question);

            bool answered = false;
            bool wasCorrect = false;

            void OnGateHit(int idx)
            {
                answered = true;
                wasCorrect = idx == _correctGateIndex;
            }

            foreach (var gate in _activeGates)
                gate.onPlayerEnter += OnGateHit;

            if (player != null) player.RunForward(playerRunSpeed);
            if (competitor != null) competitor.RunForward(playerRunSpeed);

            float timeout = gateSpawnDistance / playerRunSpeed + 5f;
            float timer = 0;
            while (!answered && timer < timeout)
            {
                timer += Time.deltaTime;
                yield return null;
            }

            /*
            if (player != null) player.Stop();
            if (competitor != null) competitor.Stop();
            */

            foreach (var gate in _activeGates)
                gate.onPlayerEnter -= OnGateHit;

            _state = McqGameState.AnswerFeedback;
            yield return ProcessAnswer(answered && wasCorrect);


            foreach (var gate in _activeGates)
            {
                if (gate != null)
                {
                    DOTween.Kill(gate.transform);
                    gate.transform.DOScale(Vector3.zero, 0.3f)
                        .SetEase(Ease.InBack)
                        .OnComplete(() => { if (gate != null) Destroy(gate.gameObject); });
                }
            }
            _activeGates.Clear();

            yield return new WaitForSeconds(0.5f);
            _state = McqGameState.BetweenQuestions;
            //if (player != null) yield return player.MoveToNextLane(0.4f);
            if (questionDisplay != null) questionDisplay.Hide();
        }

        private IEnumerator ProcessAnswer(bool correct)
        {
            if (correct)
            {
                _correctCount++;
                _streak++;
                if (_streak > _bestStreak) _bestStreak = _streak;
                int points = 100;
                if (_streak >= streakBonusThreshold)
                    points += (_streak - (int)streakBonusThreshold + 1) * 25;
                _score += points;

                ShowCorrectFeedback(points);

                var audio = SSAudioManager.Instance;
                if (audio != null)
                {
                    if (audio.sfxCorrect != null) audio.PlayCorrect();
                    else audio.PlayCorrectBeep();
                }
                var particles = SSParticleManager.Instance;
                if (particles != null && player != null)
                    particles.PlayCorrectBurst(player.transform.position + Vector3.up * 2f);
            }
            else
            {
                _wrongCount++;
                _streak = 0;
                _lives--;
                ShowWrongFeedback();

                var audio = SSAudioManager.Instance;
                if (audio != null)
                {
                    if (audio.sfxWrong != null) audio.PlayWrong();
                    else audio.PlayWrongBeep();
                }
                var particles = SSParticleManager.Instance;
                if (particles != null && player != null)
                    particles.PlayWrongBurst(player.transform.position + Vector3.up * 2f);

                if (uiManager != null) uiManager.SetLives(_lives, totalLives);
                onLifeLost?.Invoke(_lives);
            }

            if (uiManager != null) { uiManager.SetScore(_score); uiManager.SetStreak(_streak); }
            onAnswerGiven?.Invoke(correct);
            onScoreChanged?.Invoke(_score, _streak);
            yield return new WaitForSeconds(feedbackDisplayTime);
        }


        private void SpawnGates(McqQuestion question)
        {
            string[] answers = question.GetShuffledAnswers(out int correctIdx);
            _correctGateIndex = correctIdx;
            _activeGates.Clear();

            if (questionDisplay != null)
                questionDisplay.ShowAnswers(answers);

            float playerZ = player != null ? player.transform.position.z : 0f;


            Vector3 basePos = new Vector3(0f, 0f, playerZ + gateSpawnDistance);

            float totalWidth = (answers.Length - 1) * gateSpacing;
            float startX = -totalWidth / 2f;

            for (int i = 0; i < answers.Length; i++)
            {
                Vector3 gatePos = basePos + Vector3.right * (startX + i * gateSpacing);
                var gate = CreateGate(gatePos, i, answers[i], i == correctIdx);
                _activeGates.Add(gate);

                gate.transform.localScale = Vector3.zero;
                gate.transform.DOScale(Vector3.one, 0.5f)
                    .SetDelay(i * 0.1f)
                    .SetEase(Ease.OutBack);
            }
        }

        private McqGateController CreateGate(Vector3 position, int index,
            string answerText, bool isCorrect)
        {
            GameObject gatePrefab = prefabBuilder != null ? prefabBuilder.GetGatePrefab() : null;

            GameObject go;
            if (gatePrefab == null)
            {
                go = new GameObject($"Gate_{index}");
                go.transform.position = position;
            } else
            {
                go = Instantiate(gatePrefab, position, Quaternion.identity);
            }
            
            if (gateParent != null) go.transform.SetParent(gateParent);

            McqGateController gate;
            if (gatePrefab == null)
            {
                gate = go.AddComponent<McqGateController>();
            } else
            {
                gate = go.GetComponent<McqGateController>();
            }

            gate.Setup(index, answerText, isCorrect);
            return gate;
        }


        private void ShowCorrectFeedback(int points)
        {
            if (uiManager != null)
            {
                string msg = _streak >= streakBonusThreshold
                    ? $"ممتاز! +{points} (سلسلة {_streak}×) ✨"
                    : $"صحيح! +{points} ✓";
                uiManager.ShowFeedback(msg, true);
            }
            foreach (var g in _activeGates)
            {
                if (g == null) continue;
                if (g.GateIndex == _correctGateIndex)
                {
                    g.PlayCorrectAnimation();
                    if (questionDisplay != null) questionDisplay.PlayCorrectAnimation(g.GateIndex);
                }
                else
                {
                    g.PlayFadeOut();
                    if (questionDisplay != null) questionDisplay.PlayFadeOut(g.GateIndex);
                }
            }
        }

        private void ShowWrongFeedback()
        {
            if (uiManager != null) uiManager.ShowFeedback("خطأ! ✗", false);

            foreach (var g in _activeGates)
            {
                if (g == null) continue;
                if (g.GateIndex == _correctGateIndex)
                {
                    g.PlayRevealCorrect();
                    if (questionDisplay != null) questionDisplay.PlayRevealCorrect(g.GateIndex);
                }
                else if (g.WasEntered)
                {
                    g.PlayWrongAnimation();
                    if (questionDisplay != null) questionDisplay.PlayWrongAnimation(g.GateIndex);
                }
            }

            if (Camera.main != null)
            {
                DOTween.Kill(Camera.main.transform, "camShake");
                Camera.main.transform.DOShakePosition(0.4f, 0.3f, 15, 90f, false, true)
                    .SetEase(Ease.OutQuad).SetId("camShake");
            }
        }

        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();

            yield return new WaitForSeconds(0.5f);
            if (uiManager != null)
                uiManager.ShowResults(_score, _correctCount, _wrongCount,
                    _bestStreak, _questions.Length, true);
            onGameComplete?.Invoke(_score);
        }

        private IEnumerator GameOverSequence()
        {
            var audio = SSAudioManager.Instance;
            if (audio != null)
            { if (audio.sfxDefeat != null) audio.PlayDefeat(); else audio.PlayFailBuzz(); }

            yield return new WaitForSeconds(0.5f);
            if (uiManager != null)
                uiManager.ShowResults(_score, _correctCount, _wrongCount,
                    _bestStreak, _questions.Length, false);
            onGameOver?.Invoke();
        }

        public int Score => _score;
        public int Lives => _lives;
        public int Streak => _streak;
        public int CurrentQuestionIndex => _currentIndex;
        public int TotalQuestions => _questions?.Length ?? 0;
    }
}
