using System;
using Cybe;
using DG.Tweening;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

namespace Sources.Gui
{
    public class GuiController : MonoBehaviour
    {
        [SerializeField] private Player _player;

        [Header("UI elements")] 
        [Header("Experience")] 
        [SerializeField] private Image _experienceBar;
        [SerializeField] private TextMeshProUGUI _experienceAmountText;
        [SerializeField] private TextMeshProUGUI _experienceProcentText;
        [SerializeField] private TextMeshProUGUI _levelText;

        [Header("Health")]
        [SerializeField] private Image _healthBar;
        [SerializeField] private TextMeshProUGUI _healthAmountText;
    
        [Header("Etc")]
        [SerializeField] private GameObject _crosshair;
        [SerializeField] private Image _transitionFader;
        [SerializeField] private Image _damageFader;
    
        [Header("Research")]
        [SerializeField] private TextMeshProUGUI _skillPointsText;
        [SerializeField] private GameObject _researchPanel;
        
        [Header("Teleporting")] 
        [SerializeField] private Image _teleporingBar;
        [SerializeField] private GameObject _teleportingPanel;
        
        [Header("Kills")]
        [SerializeField] private Image _killsBar;
        [SerializeField] private GameObject _killsPanel;
        [SerializeField] private TextMeshProUGUI _killsAmountText;
                
        [Header("Dialogs")]
        [SerializeField] private TextMeshProUGUI _dialogText;
        [SerializeField] private TextMeshProUGUI _dialogAuthorText;
        [SerializeField] private TextMeshProUGUI _dialogShowNextText;
        [SerializeField] private GameObject _dialogPanel;
                
        [Header("Settings")]
        [SerializeField] private Slider _sensitivitySlider;
        [SerializeField] private Slider _volumeSlider;
        [SerializeField] private GameObject _settingsPanel;
        [SerializeField] private Button _closeButton;
        [SerializeField] private CameraController _cameraController;
        [SerializeField] private AudioManager _audioManager;

        private bool _isSettingsScreenOpened;
        
        private void Start()
        {
            _researchPanel.SetActive(false);
            _crosshair.SetActive(false);
            _dialogPanel.SetActive(false);
            _settingsPanel.SetActive(false);
            _transitionFader.gameObject.SetActive(false);
            _transitionFader.color = new Color(1, 1, 1, 0);
            _damageFader.gameObject.SetActive(false);
            _damageFader.color = new Color(1, 0, 0, 0);
            SetTeleportingProgress(0);
            
            SetMouseLocked(true);

            _player.OnDamaged += OnPlayerDamaged;
            
            // Settings
            _closeButton.onClick.AddListener(Application.Quit);
            _sensitivitySlider.onValueChanged.AddListener(v => _cameraController.SetSensitivity(v)); // 0 .. 20?
            _volumeSlider.onValueChanged.AddListener(v => _audioManager.SetVolume(v)); // 0 .. 1
        }
        
        public void SetCrosshairVisible(bool isVisible)
        {
            _crosshair.SetActive(isVisible);
        }

        public void SetTeleportingProgress(float progress)
        {
            _teleportingPanel.SetActive(progress > 0.0001f);
            _teleporingBar.fillAmount = progress;
        }

        public void SetKillsProgress(int killed, int needed)
        {
            _killsPanel.SetActive(needed > 0 && killed < needed);
            if (needed <= 0 || killed >= needed)
                return;
            
            _killsAmountText.text = $"{killed} / {needed}";
            _killsBar.fillAmount = (float) killed / needed;
        }
        
        private void OnPlayerDamaged()
        {
            _damageFader.gameObject.SetActive(true);
            _damageFader.DOFade(0.3f, 0.2f).OnComplete(() =>
            {
                _damageFader.DOFade(0f, 0.3f).OnComplete(() => _damageFader.gameObject.SetActive(false));
            });
        }
    
        private static void SetMouseLocked(bool isLocked)
        {
            Cursor.visible = !isLocked;
            Cursor.lockState = isLocked ? CursorLockMode.Locked : CursorLockMode.None;
        }

        private void Update()
        {
            ProcessExperienceBar();
            ProcessHealthBar();
            ProcessSettings();
            ProcessResearchPanel();
        }

        private void ProcessSettings()
        {
            if (_researchPanel.activeSelf)
                return;
            
            if (Input.GetKeyDown(KeyCode.Escape))
            {
                if (_isSettingsScreenOpened)
                {
                    UnfreezeGame();
                    _isSettingsScreenOpened = false;
                    _settingsPanel.SetActive(false);
                }
                else
                {
                    FreezeGame();
                    _isSettingsScreenOpened = true;
                    _settingsPanel.SetActive(true);

                    _volumeSlider.value = _audioManager.Volume;
                    _sensitivitySlider.value = _cameraController.Sensitivity;
                }
            }
        }

        private void ProcessResearchPanel()
        {
            if (_isSettingsScreenOpened)
                return;
            
            _skillPointsText.text = $"SP: {_player.SkillPoints}";
        
            if (Input.GetKeyDown(KeyCode.C))
            {
                if (_researchPanel.activeSelf)
                {
                    _researchPanel.SetActive(false);
                    UnfreezeGame();
                }
                else
                {
                    _researchPanel.SetActive(true);
                    FreezeGame();
                }
            }

            if (_researchPanel.activeSelf && Input.GetKeyDown(KeyCode.Escape))
            {
                _researchPanel.SetActive(false);
                UnfreezeGame();
            }
        }

        private void FreezeGame()
        {
            Time.timeScale = 0;
            SetMouseLocked(false);
        }

        private void UnfreezeGame()
        {
            Time.timeScale = 1;
           
            SetMouseLocked(true);
        }

        private void ProcessHealthBar()
        {
            var hpRatio = _player.HP / _player.MaxHp;
            _healthBar.fillAmount = hpRatio;
            _healthAmountText.text = $"{(int)_player.HP} / {(int)_player.MaxHp}";
        }

        private void ProcessExperienceBar()
        {
            var maxExperience = _player.CurrentLevelMaxExperience;
            var expRatio = _player.CurrentExperience / maxExperience;
        
            _experienceBar.fillAmount = expRatio;
            _experienceProcentText.text = $"{(expRatio * 100):0.00}%";
            _experienceAmountText.text = $"{(int)_player.CurrentExperience} / {(int)maxExperience}";
            _levelText.text = $"Level: {_player.CurrentLevel}";
        }

        public void FadeInAndOut(Action onFaded = null, Action onUnfaded = null)
        {
            _transitionFader.gameObject.SetActive(true);
            _transitionFader.DOFade(1, 1f).OnComplete(() =>
            {
                onFaded?.Invoke();
                _transitionFader.DOFade(0, 1f).OnComplete(() =>
                {
                    onUnfaded?.Invoke();
                    _transitionFader.gameObject.SetActive(false);
                });
            });
        }

        public void SetDialogVisible(bool isVisible, string author = null, string text = null, bool showNext = false)
        {
            _dialogPanel.SetActive(isVisible);

            if (!string.IsNullOrEmpty(author))
            {
                _dialogAuthorText.text = author;
                _dialogText.text = text;
                _dialogShowNextText.gameObject.SetActive(showNext);
            }
        }
    }
}
