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

namespace com.al_arcade.tf
{
    using shared;

    public enum TfGameState
    { Idle, Loading, Playing, Feedback, Complete, GameOver }

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

        [Header("Game Settings")]
        [SerializeField] private int stepsToWin = 5;
        [SerializeField] private float feedbackDuration = 1.2f;
        [SerializeField] private float stepDistance = 3f;

        [Header("References")]
        public TfHandController handController;
        public TfProductionLine productionLine;
        public TfQuestionScreen questionScreen;
        public TfUIManager uiManager;

        private TfGameState _state = TfGameState.Idle;
        private TfQuestion[] _questions;
        private int _currentIndex, _progress, _score, _streak;
        private int _correctCount, _wrongCount, _totalAsked;

        private bool _waitingForAnswer;
        private int _pendingAnswer = -1;

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

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

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

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

        public void SubmitAnswer(bool answer)
        {
            if (!_waitingForAnswer) return;
            _waitingForAnswer = false;
            _pendingAnswer = answer ? 1 : 0;
        }

        public void ResetGame()
        {
            StopAllCoroutines();
            _state = TfGameState.Idle;
            _currentIndex = _progress = _score = _streak = 0;
            _correctCount = _wrongCount = _totalAsked = 0;
            _questions = null;
            _waitingForAnswer = false;
            _pendingAnswer = -1;

            if (productionLine != null) productionLine.ResetLine();
            if (questionScreen != null) questionScreen.Clear();
            if (handController != null) handController.Reset();
            if (uiManager != null) uiManager.ResetUI();
        }

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

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

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

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

        private void BeginGameplay()
        {
            _currentIndex = _progress = _score = _streak = 0;
            _correctCount = _wrongCount = _totalAsked = 0;
            _state = TfGameState.Playing;

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

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

        private IEnumerator GameLoop()
        {
            while (_progress < stepsToWin && _currentIndex < _questions.Length)
            {
                var q = _questions[_currentIndex];
                if (questionScreen != null)
                    questionScreen.ShowQuestion(q.question_text, q.source);

                _waitingForAnswer = true;
                _pendingAnswer = -1;
                _state = TfGameState.Playing;
                if (handController != null) handController.SetReady(true);

                while (_pendingAnswer < 0)
                {
                    if (Input.GetKeyDown(KeyCode.LeftArrow) || Input.GetKeyDown(KeyCode.A))
                        SubmitAnswer(true);
                    if (Input.GetKeyDown(KeyCode.RightArrow) || Input.GetKeyDown(KeyCode.D))
                        SubmitAnswer(false);
                    yield return null;
                }

                if (handController != null) handController.SetReady(false);

                _state = TfGameState.Feedback;
                _totalAsked++;
                bool playerSaidTrue = _pendingAnswer == 1;
                bool isCorrect = playerSaidTrue == q.is_true;

                if (isCorrect)
                {
                    _correctCount++;
                    _streak++;
                    _progress++;
                    _score += 100 + (_streak > 2 ? (_streak - 2) * 25 : 0);

                    if (handController != null) handController.PlayCorrectFeedback(playerSaidTrue);
                    if (productionLine != null) yield return productionLine.MoveForward(stepDistance);
                    if (questionScreen != null) questionScreen.ShowFeedback(true, _streak);

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

                    var particles = SSParticleManager.Instance;
                    if (particles != null && Camera.main != null)
                        particles.PlayCorrectBurst(Camera.main.transform.position +
                            Camera.main.transform.forward * 3f);
                }
                else
                {
                    _wrongCount++;
                    _streak = 0;
                    _progress = Mathf.Max(0, _progress - 1);

                    if (handController != null) handController.PlayWrongFeedback(playerSaidTrue);
                    if (productionLine != null) yield return productionLine.MoveBackward(stepDistance);
                    if (questionScreen != null) questionScreen.ShowFeedback(false, 0);

                    var audio = SSAudioManager.Instance;
                    if (audio != null)
                    { if (audio.sfxWrong != null) audio.PlayWrong(); else audio.PlayWrongBeep(); }

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

                onAnswerGiven?.Invoke(isCorrect);
                onProgressChanged?.Invoke(_progress);
                if (uiManager != null)
                {
                    uiManager.SetProgress(_progress, stepsToWin);
                    uiManager.SetScore(_score);
                    uiManager.SetStreak(_streak);
                }

                yield return new WaitForSeconds(feedbackDuration);
                _currentIndex++;
                if (_currentIndex >= _questions.Length) _currentIndex = 0;
            }

            if (_progress >= stepsToWin)
            {
                _state = TfGameState.Complete;
                yield return VictorySequence();
            }
        }

        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 (productionLine != null) yield return productionLine.ProductComplete();
            yield return new WaitForSeconds(0.5f);

            if (uiManager != null)
                uiManager.ShowResults(_score, _correctCount, _wrongCount, true);
            onGameComplete?.Invoke();
        }

        public int Progress => _progress;
        public int StepsToWin => stepsToWin;
        public int Score => _score;
    }
}
