using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using HISPlayerAPI;

public class HISPlayerSample : HISPlayerManager
{
    [Header("Misc")]
    public GameObject UI;
    public GameObject settingsPanel;

    [Header("Playback Controller")]
    public Button playPauseButton;
    public Button muteButton;
    public Button subtitlesButton;
    public Button restartButton;
    public Slider volumeSlider;
    public TMP_Dropdown resolutionDropDown;
    public TMP_Dropdown captionsDropdown;
    public TMP_Dropdown audioDropdown;
    public Slider seekBar;
    public bool mute;

    [Header("Information")]
    public TextMeshProUGUI currTimeText;
    public TextMeshProUGUI totalTimeText;
    public TextMeshProUGUI subtitlesText;
    public TextMeshProUGUI speedRateText;

    [Header("Resources")]
    public Sprite playSprite;
    public Sprite pauseSprite;
    public Sprite restartSprite;
    public Sprite muteSprite;
    public Sprite unmuteSprite;

    private HISPlayerTrack[] videoTracks = null;
    private HISPlayerCaptionTrack[] captions = null;
    private HISPlayerAudioTrack[] audios = null;
    private bool showSubtitles = false;
    private int streamIndex = 0;
    private long milliseconds;
    private bool showSettings = false;
    private bool showControls = false;
    private bool isPlaying;
    private bool isPlaybackReady = false;
    private int currentVideoIndex = 0;
    private long msWhenNetworkLost;
    private bool updateSettings = true;

    #region UNITY_FUNCTIONS

    protected override void Awake()
    {
        Screen.orientation = ScreenOrientation.LandscapeLeft;

        // Flip texture vertically for Android build
        multiStreamProperties[0].FlipTextureVertically = true;

        base.Awake();
        SetUpPlayer();

        isPlaying = multiStreamProperties[0].autoPlay;
        milliseconds = 0;

        playPauseButton.image.sprite = isPlaying ? pauseSprite : playSprite;
        muteButton.image.sprite = mute ? muteSprite : unmuteSprite;
        subtitlesText.text = "";
        StartCoroutine(StartSomeValues());
    }

    private void Update()
    {
        UpdateVideoPosition();

        if (!showSettings)
            return;

        audioDropdown.RefreshShownValue();
        captionsDropdown.RefreshShownValue();
        resolutionDropDown.RefreshShownValue();
    }

    void OnApplicationFocus(bool hasFocus)
    {
        if (!isPlaybackReady)
            return;

        if (!hasFocus)
        {
            Pause(streamIndex);
            return;
        }

        if (isPlaying)
            Play(streamIndex);
    }

    void OnApplicationQuit()
    {
        Release();
    }

    #endregion

    #region PLAYBACK_CONTROLLER

    public void RestartPlayer()
    {
        isPlaying = true;
        Seek(streamIndex, 0);
        Play(streamIndex);
        restartButton.gameObject.SetActive(false);
        playPauseButton.gameObject.SetActive(true);
        playPauseButton.image.sprite = pauseSprite;
        totalTimeText.text = ConvertTime(GetVideoDuration(streamIndex));
        seekBar.maxValue = GetVideoDuration(streamIndex);
    }

    public void TogglePlayPause()
    {
        if (isPlaying)
        {
            Pause(streamIndex);
        }
        else
        {
            Play(streamIndex);
        }

        isPlaying = !isPlaying;
        playPauseButton.image.sprite = isPlaying ? pauseSprite : playSprite;
    }

    public void StopCurrentStream()
    {
        playPauseButton.image.sprite = playSprite;
        isPlaying = false;
        milliseconds = 0;
        Stop(streamIndex);
    }

    public void Forward(int ms)
    {
        milliseconds = GetVideoPosition(streamIndex) + ms;
        Seek(streamIndex, milliseconds);
    }

    public void SliderSeek()
    {
        milliseconds = (long)seekBar.value;
        Seek(streamIndex, milliseconds);
    }

    public void NextPlayback()
    {
        currentVideoIndex++;
        if (currentVideoIndex >= multiStreamProperties[streamIndex].url.Count)
            currentVideoIndex = 0;

        isPlaybackReady = false;
        ChangeVideoContent(streamIndex, currentVideoIndex);
        StartCoroutine(StartSomeValues());
        Play(streamIndex);
        isPlaying = true;
        playPauseButton.image.sprite = pauseSprite;
    }

    public void PreviousPlayback()
    {
        currentVideoIndex--;
        if (currentVideoIndex < 0)
            currentVideoIndex = multiStreamProperties[streamIndex].url.Count - 1;

        isPlaybackReady = false;
        ChangeVideoContent(streamIndex, currentVideoIndex);
        StartCoroutine(StartSomeValues());
        Play(streamIndex);
        isPlaying = true;
        playPauseButton.image.sprite = pauseSprite;
    }

    public void ChangeVolume()
    {
        if (mute)
        {
            mute = false;
            muteButton.image.sprite = unmuteSprite;
        }

        SetVolume(streamIndex, volumeSlider.value);
    }

    public void ToggleMute()
    {
        mute = !mute;
        SetVolume(streamIndex, mute ? 0.0f : volumeSlider.value);
        muteButton.image.sprite = mute ? muteSprite : unmuteSprite;
    }

    public void ChangeSpeedRate()
    {
        float currentSpeed = GetPlaybackSpeedRate(streamIndex);
        float newSpeed = 1.0f;
        switch (currentSpeed)
        {
            case 1.0f:
                newSpeed = 1.25f;
                speedRateText.text = "x1.25";
                break;
            case 1.25f:
                newSpeed = 1.5f;
                speedRateText.text = "x1.5";
                break;
            case 1.5f:
                newSpeed = 2.0f;
                speedRateText.text = "x2.0";
                break;
            case 2.0f:
                newSpeed = 8.0f;
                speedRateText.text = "x8.0";
                break;
            case 8.0f:
                newSpeed = 1.0f;
                speedRateText.text = "x1.0";
                break;
            default:
                break;
        }

        SetPlaybackSpeedRate(streamIndex, newSpeed);
    }

    #endregion

    #region TRACK_CONTROLLER

    public void ChangeResolution()
    {
        SelectTrack(streamIndex, resolutionDropDown.value); //This action will disable ABR
    }

    public void ChangeSubtitles()
    {
        SelectCaptionTrack(streamIndex, captionsDropdown.value);
    }

    public void ChangeAudioTrack()
    {
        SelectAudioTrack(streamIndex, audioDropdown.value);
    }

    public void ToggleSubtitles()
    {
        showSubtitles = !showSubtitles;
        EnableCaptions(0, showSubtitles);
        subtitlesText.gameObject.SetActive(showSubtitles);
        subtitlesButton.image.color = showSubtitles ? Color.green : Color.white;
    }

    #endregion

    #region UNITY_UI
    IEnumerator StartSomeValues()
    {
        yield return new WaitUntil(() => isPlaybackReady);

        totalTimeText.text = ConvertTime(GetVideoDuration(streamIndex));
        seekBar.maxValue = GetVideoDuration(streamIndex);
        muteButton.image.sprite = mute ? muteSprite : unmuteSprite;
        SetVolume(streamIndex, mute ? 0.0f : volumeSlider.value);
    }

    public void ToggleShowUI()
    {
        showControls = !showControls;
        UI.gameObject.SetActive(showControls);
    }

    public void ShowSettings(bool show)
    {
        showSettings = show;
        settingsPanel.SetActive(showSettings);
        if (showSettings)
        {
            isPlaying = false;
            Pause(streamIndex);
        }
        else
        {
            isPlaying = true;
            Play(streamIndex);
        }

        playPauseButton.image.sprite = isPlaying ? pauseSprite : playSprite;

        if (Application.platform != RuntimePlatform.Android)
        {
            updateSettings = true;
            videoTracks = isPlaybackReady ? GetTracks(streamIndex) : null;
            captions = isPlaybackReady ? GetCaptionTrackList(streamIndex) : null;
            audios = isPlaybackReady ? GetAudioTrackList(streamIndex) : null;
            UpdateSettingsPanel();
        }
    }

    public void UpdateSettingsPanel()
    {
        if (!updateSettings)
            return;

        int i = 0;
        resolutionDropDown.ClearOptions();
        if (videoTracks != null)
        {
            foreach (var video in videoTracks)
            {
                resolutionDropDown.options.Add(new TMP_Dropdown.OptionData()
                {
                    text = /*"Resolution: " + */videoTracks[i].width.ToString() + " x " + videoTracks[i].height.ToString()
                });

                i++;
            }
        }

        if (resolutionDropDown.options.Count == 0)
            resolutionDropDown.options.Add(new TMP_Dropdown.OptionData()
            {
                text = "Resolution not available"
            });

        i = 0;
        captionsDropdown.ClearOptions();
        if (captions != null)
        {
            foreach (var channel in captions)
            {
                captionsDropdown.options.Add(new TMP_Dropdown.OptionData()
                {
                    text = /*"Subtitles: " + */captions[i].language
                });

                i++;
            }

        }

        if (captionsDropdown.options.Count == 0)
            captionsDropdown.options.Add(new TMP_Dropdown.OptionData()
            {
                text = "Subtitle not available"
            });

        i = 0;
        audioDropdown.ClearOptions();
        if (audios != null)
        {
            foreach (var channel in audios)
            {
                audioDropdown.options.Add(new TMP_Dropdown.OptionData()
                {
                    text = /*"Audio: " + */audios[i].language
                });

                i++;
            }
        }

        if (audioDropdown.options.Count == 0)
            audioDropdown.options.Add(new TMP_Dropdown.OptionData()
            {
                text = "Audio not available"
            });

        updateSettings = false;
    }

    private void UpdateVideoPosition()
    {
        if (!isPlaybackReady)
            return;
        long ms = GetVideoPosition(streamIndex);
        currTimeText.text = ConvertTime(ms);
        seekBar.value = ms;
    }

    #endregion

    #region MISC

    private string ConvertTime(long miliseconds)
    {
        int hours = (int)(miliseconds / (1000 * 60 * 60));
        int minutes = (int)((miliseconds / (1000 * 60)) % 60);
        int seconds = (int)((miliseconds / 1000) % 60);

        string timeStr;

        if (minutes < 10 && seconds < 10)
        {
            timeStr = hours + ":0" + minutes + ":0" + seconds;
        }
        else if (minutes < 10)
        {
            timeStr = hours + ":0" + minutes + ":" + seconds;
        }
        else if (seconds < 10)
        {
            timeStr = hours + ":" + minutes + ":0" + seconds;
        }
        else
        {
            timeStr = hours + ":" + minutes + ":" + seconds;
        }

        return timeStr;
    }

    #endregion


    // HISPLAYER EVENTS OVERRIDE
    protected override void EventPlaybackPlay(HISPlayerEventInfo eventInfo)
    {
        base.EventPlaybackPlay(eventInfo);
    }

    protected override void EventVideoSizeChange(HISPlayerEventInfo eventInfo)
    {
        base.EventVideoSizeChange(eventInfo);

#if PLATFORM_ANDROID
        if (!isPlaybackReady)
        {
            updateSettings = true;
            videoTracks = GetTracks(streamIndex);
            captions = GetCaptionTrackList(streamIndex);
            audios = GetAudioTrackList(streamIndex);
            UpdateSettingsPanel();
        }

        if (videoTracks != null)
        {
            int i = 0;
            bool stop = false;
            while (i < videoTracks.Length && !stop)
            {
                if ((int)eventInfo.param1 == videoTracks[i].width &&
                    (int)eventInfo.param2 == videoTracks[i].height)
                {
                    resolutionDropDown.SetValueWithoutNotify(i);
                    stop = true;
                }

                i++;
            }
        }
#endif
    }

    protected override void EventPlaybackReady(HISPlayerEventInfo eventInfo)
    {
        base.EventPlaybackReady(eventInfo);
        isPlaybackReady = true;
    }

    protected override void EventTextRender(HISPlayerCaptionElement subtitlesInfo)
    {
        base.EventTextRender(subtitlesInfo);
        subtitlesText.text = subtitlesInfo.caption;
    }

    protected override void EventEndOfPlaylist(HISPlayerEventInfo eventInfo)
    {
        base.EventEndOfPlaylist(eventInfo);
        ChangeVideoContent(streamIndex, 0);
        isPlaying = false;
        Seek(streamIndex, 0);
        Pause(streamIndex);
        restartButton.gameObject.SetActive(true);
        playPauseButton.gameObject.SetActive(false);
    }

    protected override void EventAutoTransition(HISPlayerEventInfo eventInfo)
    {
        base.EventAutoTransition(eventInfo);
        totalTimeText.text = ConvertTime(GetVideoDuration(streamIndex));
        seekBar.maxValue = GetVideoDuration(streamIndex);
    }

    protected override void EventNetworkConnected(HISPlayerEventInfo eventInfo)
    {
        base.EventNetworkConnected(eventInfo);

        Seek(streamIndex, msWhenNetworkLost);
        Play(streamIndex);
    }

    protected override void ErrorNetworkFailed(HISPlayerErrorInfo errorInfo)
    {
        base.ErrorNetworkFailed(errorInfo);
        msWhenNetworkLost = GetVideoPosition(streamIndex);
        Debug.Log("MS WHEN NETWORK LOST: " + msWhenNetworkLost);
    }
}
