using Microsoft.WindowsAPICodePack.Shell;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;

namespace VideoPlayer
{

    public enum VideoState
    {
        play, stop, pause
    }
    /// <summary>
    /// WenVideoPlayer.xaml 的互動邏輯
    /// </summary>
    public partial class VideoPlayer : UserControl
    {
        public event EventHandler OnVideoComplete;

        public event EventHandler<VideoState> OnVideoStateChanged;

        /// <summary> 取得有總共有多少影片正在撥放 </summary>
        /// <return> 撥放中的數量 </return>
        public static int playingCount
        {
            get
            {
                int count = 0;
                foreach (VideoPlayer player in playerCreated)
                {
                    if (player.IsPlaying)
                        count++;
                }
                return count;
            }
        }

        public static void ReleaseAll()
        {
            VideoPlayer[] listClone = new VideoPlayer[playerCreated.Count];
            playerCreated.CopyTo(listClone);
            foreach (VideoPlayer player in listClone)
            {
                player.ReleaseResource();
            }
        }

        /// <summary> 阻擋對Player觸控的事件 </summary>
        public bool manipulationLocked = false;

        private static List<VideoPlayer> playerCreated = new List<VideoPlayer>();

        private MediaElement mediaSource;
        private bool stopRequest = false;
        private bool progressSliderChanging = false;
        private DispatcherTimer toolbarHideTimer = new DispatcherTimer();
        private const int timerInterval = 3000;  //隱藏工具時間
        private string _videoPath;
        private MediaTimeline mt;
        private bool mediaLoadComplete = false;
        private VideoState beginBehavier;
        private double videoRatio = 0;
        private Size videoSize = new Size();

        private VideoState currentVideoState;

        private double videoLength;
        public double VideoLength
        {
            get
            {
                return videoLength;
            }
        }
        public bool IsPlaying
        {
            get
            {
                return !(mediaSource.Clock.IsPaused || mediaSource.Clock.CurrentState == ClockState.Stopped);
            }
        }

        public Size VideoSize
        {
            get
            {
                return videoSize;
            }
        }

        public string VideoPath
        {
            get
            {
                return _videoPath;
            }
        }

        public void Stop()
        {
            stop_TouchDown(null, null);
        }

        public void Play()
        {
            uxPlayButton_TouchUp(null, null);
        }

        public void Pause()
        {
            pause_TouchDown(null, null);
        }

        public void IncereaseVolume(double volume = 1)
        {
            setVolume(uxVolumeSlider.Value + volume);
        }

        public void DecressVolume(double volume = 1)
        {
            setVolume(uxVolumeSlider.Value - volume);
        }

        public void SetVolume(double volume = 1)
        {
            setVolume(volume);
        }

        public void UpdateScale(double scale)
        {
            double ratio = 1;
            ((ScaleTransform)uxControlPanel.RenderTransform).ScaleY = 1 / (scale);
            uxControlPanel.ColumnDefinitions[1].Width = new GridLength(30 / (scale * ratio), GridUnitType.Pixel);
            uxControlPanel.ColumnDefinitions[3].Width = new GridLength(30 / (scale * ratio), GridUnitType.Pixel);
            uxControlPanel.ColumnDefinitions[7].Width = new GridLength(30 / (scale * ratio), GridUnitType.Pixel);

            uxControlPanel.ColumnDefinitions[0].Width = new GridLength(15 / (scale * ratio), GridUnitType.Pixel);
            uxControlPanel.ColumnDefinitions[2].Width = new GridLength(15 / (scale * ratio), GridUnitType.Pixel);
            uxControlPanel.ColumnDefinitions[4].Width = new GridLength(15 / (scale * ratio), GridUnitType.Pixel);
            uxControlPanel.ColumnDefinitions[6].Width = new GridLength(15 / (scale * ratio), GridUnitType.Pixel);
            uxControlPanel.ColumnDefinitions[8].Width = new GridLength(15 / (scale * ratio), GridUnitType.Pixel);

            ((ScaleTransform)uxPlayButton.RenderTransform).ScaleX = 1 / scale;
            ((ScaleTransform)uxPlayButton.RenderTransform).ScaleY = 1 / scale;
        }

        public void ReleaseResource()
        {
            mediaSource.Clock.Completed -= Video_Completed;
            mediaSource.MediaOpened -= MediaSource_MediaOpened;
            mediaSource.Clock.CurrentTimeInvalidated -= media_CurrentTimeInvalidated;
            mediaSource.Clock.Controller.Stop();
            mt.Source = null;
            mediaSource.Clock = null;
            mediaSource.Source = null;
            mediaSource = null;
            playerCreated.Remove(this);
            Console.WriteLine("WenVideoPlayer_ReleaseResource");
        }

        public FrameworkElement DetatchController()
        {
            if (uxControlPanel.Parent is Panel parentPanel)
                parentPanel.Children.Remove(uxControlPanel);
            uxControlPanel.IsVisibleChanged += (s, e) => {
                if (uxControlPanel.Visibility == Visibility.Visible)
                {
                    toolbarHideTimer.Stop();
                    toolbarHideTimer.Start();
                }
            };
            return uxControlPanel;
        }

        public VideoPlayer(Uri videoPath, VideoState beginBehavier = VideoState.play)
        {
            InitializeComponent();
            currentVideoState = beginBehavier;
            //Stylus.SetIsPressAndHoldEnabled(this, false);
            //this.IsManipulationEnabled = true;
            _videoPath = videoPath.OriginalString;
            this.beginBehavier = beginBehavier;

            this.Unloaded += WenVideoPlayer_Unloaded;
            //this.MouseLeave += WenVideoPlayer_MouseLeave;
            //create preview image
            ShellFile shellFile = ShellFile.FromFilePath(_videoPath);
            ((Image)uxCoverImageParent.Children[0]).Source = shellFile.Thumbnail.ExtraLargeBitmapSource;
            //((Image)uxCoverImageParent.Children[0]).Stretch = Stretch.None;
            //this.Height = Convert.ToDouble(shellFile.Properties.System.Video.FrameHeight.Value);
            //this.Width = Convert.ToDouble(shellFile.Properties.System.Video.FrameWidth.Value);
            videoSize.Width = Convert.ToDouble(shellFile.Properties.System.Video.FrameWidth.Value);
            videoSize.Height = Convert.ToDouble(shellFile.Properties.System.Video.FrameHeight.Value);
            double nanoseconds = -1;
            Double.TryParse(shellFile.Properties.System.Media.Duration.Value.ToString(), out nanoseconds);
            videoLength = nanoseconds == -1 ? -1 : nanoseconds / 10000000;

            this.Loaded += VideoPlayer_Loaded;

            //add video player
            mediaSource = new MediaElement();
            //mediaSource.Height = Convert.ToDouble(shellFile.Properties.System.Video.FrameHeight.Value);
            //mediaSource.Width = Convert.ToDouble(shellFile.Properties.System.Video.FrameWidth.Value);
            //mediaSource.Stretch = Stretch.Uniform;

            mt = new MediaTimeline(videoPath);
            mediaSource.Clock = mt.CreateClock();
            mediaSource.Clock.CurrentTimeInvalidated += media_CurrentTimeInvalidated;
            mediaSource.Clock.Completed += Video_Completed;
            mediaSource.LoadedBehavior = MediaState.Stop;
            mediaSource.MediaOpened += MediaSource_MediaOpened;
            mediaSource.VerticalAlignment = VerticalAlignment.Bottom;
            RenderOptions.SetBitmapScalingMode(mediaSource, BitmapScalingMode.HighQuality);
            //mediaSource.Margin = new Thickness(0, -10, 0, -10);

            toolbarHideTimer.Interval = TimeSpan.FromMilliseconds(timerInterval);
            toolbarHideTimer.Tick += AutoHideControlTimer_Tick;

            uxVideoPanel.Children.Add(mediaSource);

            this.UpdateLayout();
            playerCreated.Add(this);
        }

        private void VideoPlayer_Loaded(object sender, RoutedEventArgs e)
        {
            //video Height / Width info can get from this.Width & this.Height
            //videoRatio = (double)videoSize.Width / videoSize.Height;
            //double thisRatio = this.ActualWidth / this.ActualHeight;
            //if (videoRatio > thisRatio)
            //{
            //    this.Height = this.ActualWidth / videoRatio;
            //}
            //else
            //{
            //    this.Width = this.ActualHeight * videoRatio;
            //}
            uxVideoPanel.Height = this.Height;
            uxVideoPanel.Width = this.ActualWidth;
            //workaround
            mediaSource.Height = this.Height + 6;
            mediaSource.Width = this.ActualWidth + 6;
        }

        private void WenVideoPlayer_MouseLeave(object sender, RoutedEventArgs e)
        {
            return;
            mediaSource.Clock.Controller.Pause();
            uxControlPanel.Visibility = Visibility.Collapsed;
            uxVolumeGrid.Visibility = Visibility.Collapsed;
            uxPlayButtonParent.Visibility = Visibility.Visible;
        }

        private void WenVideoPlayer_Unloaded(object sender, RoutedEventArgs e)
        {
            if (mediaSource != null)
            {
                //mediaSource.Clock.Completed -= Video_Completed;
                //mediaSource.MediaOpened -= MediaSource_MediaOpened;
                //mediaSource.Clock.CurrentTimeInvalidated -= media_CurrentTimeInvalidated;
                mediaSource.Clock.Controller.Stop();
                mt.Source = null;
                //mediaSource.Clock = null;
                mediaSource.Source = null;
                //mediaSource = null;
                playerCreated.Remove(this);
            }
        }

        private void AutoHideControlTimer_Tick(object sender, EventArgs e)
        {
            uxControlPanel.Visibility = Visibility.Collapsed;
            uxVolumeGrid.Visibility = Visibility.Collapsed;
            toolbarHideTimer.Stop();
        }

        private void Video_Completed(object sender, EventArgs e)
        {
            mediaSource.Clock.Controller.Stop();
            uxControlPanel.Visibility = Visibility.Collapsed;
            uxVolumeGrid.Visibility = Visibility.Collapsed;
            if (toolbarHideTimer.IsEnabled)
            {
                toolbarHideTimer.Stop();
            }
            uxPlayButtonParent.Visibility = Visibility.Visible;

            OnVideoComplete?.Invoke(this, new EventArgs());
        }

        private void MediaSource_MediaOpened(object sender, RoutedEventArgs e)
        {
            mediaLoadComplete = true;
            mediaSource.Volume = uxVolumeSlider.Value / 10; //0.5;
            //uxVolumeSlider.Value = 5;

            //mt.Source.UserInfo.Count();

            if (beginBehavier == VideoState.play)
            {
                Play();
            }
            else if (beginBehavier == VideoState.stop)
            {
                mediaSource.Clock.Controller.Stop();
                Stop();
            }
            uxCoverImageParent.Visibility = Visibility.Collapsed;
            uxPlayButtonParent.Visibility = Visibility.Collapsed;
            //WenVideoPlayerIsPlaying += 1;
        }

        private void media_CurrentTimeInvalidated(object sender, EventArgs e)
        {
            if (stopRequest == true)
            {
                mediaSource.Clock.Controller.Stop();
                stopRequest = false;
            }
            if (mediaSource.NaturalDuration.HasTimeSpan && mediaSource.Clock.CurrentTime != null && progressSliderChanging != true)
            {
                uxProgressSlider.Value = 10 * mediaSource.Clock.CurrentTime.Value.TotalMilliseconds / mediaSource.NaturalDuration.TimeSpan.TotalMilliseconds;
            }
        }

        private void uxVideoPanel_TouchDown(object sender, TouchEventArgs e)
        {
            //if (uxControlPanel.Visibility == Visibility.Collapsed)
            //{
            //    uxControlPanel.Visibility = Visibility.Visible;
            //    toolbarHideTimer.Start();
            //}
            //else if (uxControlPanel.Visibility == Visibility.Visible)
            //{
            //    uxControlPanel.Visibility = Visibility.Collapsed;
            //    uxVolumeGrid.Visibility = Visibility.Collapsed;
            //    if (toolbarHideTimer.IsEnabled)
            //    {
            //        toolbarHideTimer.Stop();
            //    }
            //    uxPlayButtonParent.Visibility = Visibility.Visible;
            //    mediaSource.Clock.Controller.Pause();
            //}
            uxControlPanel.Visibility = Visibility.Visible;
            toolbarHideTimer.Start();
        }

        private void pause_TouchDown(object sender, TouchEventArgs e)
        {
            if (currentVideoState != VideoState.pause)
            {
                currentVideoState = VideoState.pause;

                mediaSource.Clock.Controller.Pause();
                uxControlPanel.Visibility = Visibility.Collapsed;
                uxVolumeGrid.Visibility = Visibility.Collapsed;
                uxPlayButtonParent.Visibility = Visibility.Visible;

                OnVideoStateChanged?.Invoke(this, VideoState.pause);
            }
        }

        private void stop_TouchDown(object sender, TouchEventArgs e)
        {
            if (currentVideoState != VideoState.stop)
            {
                currentVideoState = VideoState.stop;

                if (mediaLoadComplete == true)
                {
                    mediaSource.Clock.Controller.Stop();
                    uxControlPanel.Visibility = Visibility.Collapsed;
                    uxVolumeGrid.Visibility = Visibility.Collapsed;
                    if (toolbarHideTimer.IsEnabled)
                    {
                        toolbarHideTimer.Stop();
                    }
                    uxPlayButtonParent.Visibility = Visibility.Visible;
                    uxCoverImageParent.Visibility = Visibility.Visible;
                }
                else
                {
                    beginBehavier = VideoState.stop;
                }

                OnVideoStateChanged?.Invoke(this, VideoState.stop);
            }
        }

        private void uxPlayButton_TouchUp(object sender, TouchEventArgs e)
        {
            if (currentVideoState != VideoState.play)
            {

                currentVideoState = VideoState.play;

                uxPlayButtonParent.Visibility = Visibility.Collapsed;
                uxControlPanel.Visibility = Visibility.Collapsed;
                uxVolumeGrid.Visibility = Visibility.Collapsed;
                if (toolbarHideTimer.IsEnabled)
                {
                    toolbarHideTimer.Stop();
                }

                if (mediaSource.Clock.CurrentState == ClockState.Stopped)
                {
                    mediaSource.Clock.Controller.Pause();
                    mediaSource.Clock.Controller.Resume();
                    mediaSource.Clock.Controller.Begin();
                }
                else if (mediaSource.Clock.CurrentState == ClockState.Filling)
                {
                    uxCoverImageParent.Visibility = Visibility.Collapsed;
                    return;
                }

                if (mediaLoadComplete == false)
                {
                    mediaSource.Clock.Controller.Begin();
                    beginBehavier = VideoState.play;
                    return;
                }

                if (mediaSource.Clock.IsPaused == true)
                {
                    mediaSource.Clock.Controller.Resume();
                }
                else
                {
                    mediaSource.Clock.Controller.Begin();
                }
                uxCoverImageParent.Visibility = Visibility.Collapsed;

                OnVideoStateChanged?.Invoke(this, VideoState.play);
            }
        }

        private void uxProgressSlider_TouchDown(object sender, TouchEventArgs e)
        {
            progressSliderChanging = true;
            mediaSource.Clock.Controller.Pause();
            Point pt = e.GetTouchPoint((UIElement)sender).Position;
            uxProgressSlider.Value = uxProgressSlider.Maximum * (pt.X) / uxProgressSlider.ActualWidth;
            e.Handled = true;
            Console.WriteLine("uxProgressSlider_TouchDown");
        }

        private void uxProgressSlider_TouchUp(object sender, TouchEventArgs e)
        {
            progressSliderChanging = false;
            mediaSource.Clock.Controller.Resume();
        }

        private void uxProgressSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            if (progressSliderChanging == true)
            {
                mediaSource.Clock.Controller.SeekAlignedToLastTick(new TimeSpan((long)(mediaSource.NaturalDuration.TimeSpan.Ticks * uxProgressSlider.Value / 10)), new System.Windows.Media.Animation.TimeSeekOrigin());
            }
        }

        private void uxProgressSlider_TouchMove(object sender, TouchEventArgs e)
        {
            progressSliderChanging = true;
            if (mediaSource.Clock.IsPaused == false)
            {
                mediaSource.Clock.Controller.Pause();
            }
            Point pt = e.GetTouchPoint((UIElement)sender).Position;
            uxProgressSlider.Value = uxProgressSlider.Maximum * (pt.X) / uxProgressSlider.ActualWidth;
            e.Handled = true;
        }

        private void Global_TouchUp(object sender, TouchEventArgs e)
        {
            if (progressSliderChanging == true)
            {
                progressSliderChanging = false;
                mediaSource.Clock.Controller.Resume();
            }
            if (e.Source is Grid && ((Grid)e.Source) == uxPlayButtonParent)
            {
                uxPlayButton_TouchUp(sender, e);
            }
            else if (toolbarHideTimer.IsEnabled == true)
            {
                toolbarHideTimer.Stop();
                toolbarHideTimer.Start();
            }
        }

        private void uxSound_TouchDown(object sender, TouchEventArgs e)
        {
            if (uxVolumeGrid.Visibility == Visibility.Collapsed)
            {
                uxVolumeGrid.Visibility = Visibility.Visible;
                ((Storyboard)FindResource("sbShowVolSlider")).Begin();
            }
            else
            {

                Storyboard sbBuf = ((Storyboard)FindResource("sbHideVolSlider"));
                sbBuf.Completed += delegate (object s, EventArgs se)
                {
                    uxVolumeGrid.Visibility = Visibility.Collapsed;
                };
                sbBuf.Begin();
            }
        }

        private void uxVolumeGrid_TouchDown(object sender, TouchEventArgs e)
        {
            e.Handled = true;
        }

        private void uxVolumeGrid_TouchMove(object sender, TouchEventArgs e)
        {
            e.Handled = true;
        }

        private void uxVolumeSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            setVolume(e.NewValue);
        }

        private void setVolume(double volume)
        {
            if (uxVolumeSlider.Value != volume)
            {
                uxVolumeSlider.Value = volume;
                if (volume == 0)
                {
                    uxNoSound.Visibility = Visibility.Visible;
                    uxSound.Visibility = Visibility.Collapsed;
                }
                else if (uxNoSound.Visibility == Visibility.Visible) //and e.NewValue != 0
                {
                    uxNoSound.Visibility = Visibility.Collapsed;
                    uxSound.Visibility = Visibility.Visible;
                }
            }
            if (mediaSource != null && mediaSource.IsLoaded)
            {
                mediaSource.Volume = volume / 10;
            }
            
        }

        private void ResetTimer(object sender, TouchEventArgs e)
        {
            if (toolbarHideTimer.IsEnabled == true)
            {
                toolbarHideTimer.Stop();
                toolbarHideTimer.Start();
            }
        }

        private void Grid_PreviewTouchUp(object sender, TouchEventArgs e)
        {
            if (manipulationLocked == true)
            {
                e.Handled = true;
                return;
            }
        }

        private void uxVolumeSlider_TouchDown(object sender, TouchEventArgs e)
        {
            Point pt = e.GetTouchPoint((UIElement)sender).Position;
            uxVolumeSlider.Value = uxVolumeSlider.Maximum * (uxVolumeSlider.ActualHeight - pt.Y) / uxVolumeSlider.ActualHeight;
            e.Handled = true;
        }

        private void uxVolumeSlider_TouchMove(object sender, TouchEventArgs e)
        {
            Point pt = e.GetTouchPoint((UIElement)sender).Position;
            uxVolumeSlider.Value = uxVolumeSlider.Maximum * (uxVolumeSlider.ActualHeight - pt.Y) / uxVolumeSlider.ActualHeight;
            //e.Handled = true;
        }

    }
}
