using System.Collections.Generic;
using Intrepid.GameManagers;
using Intrepid.Gameplay.Entities.Player.PDA.Inputs;
using Intrepid.Sound;
using Intrepid.Utilities;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

namespace Intrepid.Gameplay.Entities.Player.PDA.UI.Applications.MusicPlayer
{
    public enum MusicPlayerStatus
    {
        None,
        Playing,
        Paused,
        Stopped,
    }
    
    public class PDAMusicPlayerUI : MonoBehaviour
    {
        private static readonly List<MusicPlayerStatus> AllowToPlay = new()
        {
            MusicPlayerStatus.None,
            MusicPlayerStatus.Paused,
            MusicPlayerStatus.Stopped,
        };
        
        private static readonly List<MusicPlayerStatus> AllowToPause = new()
        {
            MusicPlayerStatus.Playing,
        };
        
        private static readonly List<MusicPlayerStatus> AllowVolume = new()
        {
            MusicPlayerStatus.Playing,
            MusicPlayerStatus.Paused,
            MusicPlayerStatus.Stopped,
        };
        
        private static readonly List<MusicPlayerStatus> AllowPosition = new()
        {
            MusicPlayerStatus.Playing,
            MusicPlayerStatus.Paused,
        };

        [SerializeField] private TextMeshProUGUI textMesh;
        [SerializeField] private Button play;
        [SerializeField] private Button pause;
        [SerializeField] private Button stop;
        [SerializeField] private Slider volume;
        [SerializeField] private Slider position;
        [SerializeField] private float volumeStep = 0.05f;
        [SerializeField] private float positionStep = 0.05f;

        private SoundMusicData SoundMusicData { get; set; }
        public SoundObject SoundObject { get; set; }

        private MusicPlayerStatus Status { get; set; } = MusicPlayerStatus.None;

        private void Reset()
        {
            play.interactable = false;
            pause.interactable = false;
            stop.interactable = false;
            volume.interactable = false;
            position.interactable = false;
            SoundMusicData = null;
            Status = MusicPlayerStatus.None;
            DisplayNoMusic();
        }
        
        public void WhenStarting()
        {
            Reset();
        }
        
        public void WhenFinishing()
        {
            Proxy.Instance.SoundSystem.ForceStopMusic();
            Reset();
        }

        private void UpdateVolumeAndPosition()
        {
            if (SoundObject is null) return;
            volume.value = SoundObject.AudioSource.volume;
            position.value = SoundObject.AudioSource.time / SoundObject.AudioSource.clip.length; 
        }
        
        public void UpdateApplication(PDAInputs inputs)
        {
            UpdateVolumeAndPosition();
            
            if (inputs.Enter() && AllowToPlay.Contains(Status))
            {
                Play();
            }
            else if (inputs.Enter() && AllowToPause.Contains(Status))
            {
                Pause();
            }

            if (inputs.ShoulderRight() && AllowVolume.Contains(Status))
            {
                ChangeVolume(+volumeStep * Time.deltaTime);
            }
            
            if (inputs.ShoulderLeft() && AllowVolume.Contains(Status))
            {
                ChangeVolume(-volumeStep * Time.deltaTime);
            }

            if (inputs.HasTriggerInput() && AllowPosition.Contains(Status))
            {
                ChangePosition((-inputs.TriggerLeft() + inputs.TriggerRight()) * positionStep * Time.deltaTime);
            }
        }
        
        public void SelectedMusic(SoundMusicData soundMusicData)
        {
            if (soundMusicData is null)
            {
                Dbg.Always.LogError("there is no music data selected");
                return;
            }
            
            Status = MusicPlayerStatus.None;
            play.interactable = true;
            pause.interactable = false;
            stop.interactable = false;
            volume.interactable = true;
            position.interactable = true;
            position.value = 0;
            SoundMusicData = soundMusicData;
            SoundObject?.Stop();
            SoundObject = null;
            DisplayMusic();
        }

        private void DisplayNoMusic()
        {
            textMesh.text = "-";
        }

        private void DisplayMusic()
        {
            textMesh.text = Proxy.Instance.I18N.Localise(SoundMusicData.Localization);
        }

        public void ChangeVolume(float v)
        {
            if (SoundObject is null) return;
            SoundObject.AudioSource.volume += Mathf.Clamp(v, -1f, 1f);
        }
        
        public void ChangePosition(float p)
        {
            if (SoundObject is null) return;
            SoundObject.AudioSource.time += Mathf.Clamp(p, -1f, 1f) * SoundObject.AudioSource.clip.length;
        }
        
        public void Play()
        {
            Status = MusicPlayerStatus.Playing;
            play.interactable = false;
            pause.interactable = true;
            stop.interactable = true;
            volume.interactable = true;
            position.interactable = true;
            if (SoundObject is null)
            {
                SoundObject = Proxy.Instance.SoundSystem.PlayMusic(SoundMusicData.soundId, true, _ => { });
                SoundObject.AudioSource.volume = volume.value;
                position.value = 0;
                return;
            }
            SoundObject.Play();
        }

        public void Pause()
        {
            Status = MusicPlayerStatus.Paused;
            play.interactable = true;
            pause.interactable = false;
            stop.interactable = true;
            position.interactable = true;
            SoundObject.Pause();
        }

        public void Stop()
        {
            Status = MusicPlayerStatus.Stopped;
            play.interactable = true;
            pause.interactable = false;
            stop.interactable = false;
            position.interactable = false;
            position.value = 0;
            SoundObject.Stop();
            SoundObject.AudioSource.time = 0f;
        }
    }
}