using Bellwether.Utility;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
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;

namespace Bellwether.UIComponent
{
    /// <summary>
    /// Interaction logic for MediaViewer.xaml
    /// </summary>
    public partial class MediaViewer : UserControl
    {
        public MediaViewer()
        {
            InitializeComponent();
            InitStoryboard();

            AutoPlayTimer = new Timer();
            AutoPlayTimer.Interval = Setting.AutoPlayInterval * 1000;
            AutoPlayTimer.Elapsed += AutoPlayTimer_Elapsed;

            this.Loaded += ImgViewer_Loaded;
            this.Unloaded += MediaViewer_Unloaded;
        }

        #region properties
        private List<string> mediaPathList;
        public List<string> MediaPathList
        {
            get => new List<string>(mediaPathList);
            set
            {
                if (value != null)
                    mediaPathList = new List<string>(value);
            }
        }

        //private string selectedImgPath;
        public string SelectedMediaPath
        {
            get
            {
                if (mediaPathList == null || currentIndex >= mediaPathList.Count)
                    return null;
                return mediaPathList[currentIndex];
            }
        }

        private int currentIndex;
        public int CurrentIndex
        {
            get => currentIndex;
            set
            {
                if (currentIndex != value)
                {
                    //update
                    ScrollToIndex(value);
                }
            }
        }

        public double ScrollOffset
        {
            get => uxMainScroller.HorizontalOffset;
            set
            {
                uxMainScroller.ScrollToHorizontalOffset(value);
            }
        }

        private UIElement CurrentFramework;
        private UIElement PreviousFramework
        {
            get
            {
                int index = uxMainCointainer.Children.IndexOf(CurrentFramework) - 1;
                if (index > -1)
                {
                    return uxMainCointainer.Children[index];
                }
                else
                {
                    return null;
                }
            }
        }
        private UIElement NextFramework
        {
            get
            {
                int index = uxMainCointainer.Children.IndexOf(CurrentFramework) + 1;
                if (index < uxMainCointainer.Children.Count - 1)
                {
                    return uxMainCointainer.Children[index];
                }
                else
                {
                    return null;
                }
            }
        }

        #endregion

        public event EventHandler<int> OnCurrentIndexChanged;
        public event EventHandler<VideoPlayer.VideoState> OnVideoStateChanged;

        private static readonly double slipSpeedMin = 0.4;  //瞬間切頁的速度參數
        private Storyboard sbMainScrollOffsetX;
        private bool isAutoPlayEnablled = true;

        private Timer AutoPlayTimer;

        public int VideoVolume { get; set; } = 50;

        public bool IsViewingVideo
        {
            get => CurrentFramework is VideoPlayer.VideoPlayer;
        }

        public bool IsVideoPlaying
        {
            get
            {
                if (CurrentFramework is VideoPlayer.VideoPlayer videoplayer)
                {
                    return videoplayer.IsPlaying;
                }
                return false;
            }
        }

        public FrameworkElement GetCurrentController()
        {
            if (CurrentFramework is VideoPlayer.VideoPlayer videoPlayer)
            {
                return videoPlayer.DetatchController();
            }
            return null;
        }

        public void ScrollToObject(object e)
        {
            int objectIndex = -1;
            if (e is string == false) return;
            for (int tempIndex = 0; tempIndex < mediaPathList.Count; tempIndex++)
            {
                if (mediaPathList[tempIndex] == ((string)e))
                {
                    objectIndex = tempIndex;
                    break;
                }
            }
            ScrollToIndex(objectIndex);
        }

        public void ScrollToIndex(int objectIndex)
        {
            if (objectIndex != -1)
            {
                if (this.IsLoaded)
                {
                    if (objectIndex != currentIndex)
                    {
                        sbMainScrollOffsetX.Completed += SbMainScrollOffsetX_Completed;
                        FrameworkElement temp = CreateMediaFramework(objectIndex);
                        //function
                        if (objectIndex < currentIndex)
                        {
                            //insert in left
                            int currentFrameworkStackIndex = uxMainCointainer.Children.IndexOf(CurrentFramework);

                            uxMainCointainer.Children.RemoveAt(currentFrameworkStackIndex - 1);
                            uxMainCointainer.Children.Insert(currentFrameworkStackIndex - 1, temp);
                            //scroll
                            uxMainCointainer.UpdateLayout();
                            SetMainPictureScrollToPos(PreviousFramework.TransformToAncestor(uxMainCointainer).Transform(new Point(0, 0)).X);
                        }
                        else if (objectIndex > currentIndex)
                        {
                            //insert in right
                            int currentFrameworkStackIndex = uxMainCointainer.Children.IndexOf(CurrentFramework);

                            uxMainCointainer.Children.RemoveAt(currentFrameworkStackIndex + 1);
                            uxMainCointainer.Children.Insert(currentFrameworkStackIndex + 1, temp);
                            //scroll
                            uxMainCointainer.UpdateLayout();
                            SetMainPictureScrollToPos(NextFramework.TransformToAncestor(uxMainCointainer).Transform(new Point(0, 0)).X);
                        }
                        currentIndex = objectIndex;
                        CurrentFramework = temp;
                    }
                }
                else
                {
                    currentIndex = objectIndex;
                }
            }
        }

        public void TryPlayVideo()
        {
            if (CurrentFramework is VideoPlayer.VideoPlayer currentVideoPlayer)
            {
                currentVideoPlayer.Play();
            }
        }

        public void TryPauseVideo()
        {
            if (CurrentFramework is VideoPlayer.VideoPlayer currentVideoPlayer)
                currentVideoPlayer.Pause();
        }

        public void TryStopVideo()
        {
            if (CurrentFramework is VideoPlayer.VideoPlayer currentVideoPlayer)
                currentVideoPlayer.Stop();
        }

        public void Stop()
        {
            currentIndex = -1;

            if (CurrentFramework is VideoPlayer.VideoPlayer currentVideoPlayer)
                TryStopVideo();
            else
                AutoPlayTimer.Stop();
        }

        public void Play()
        {
            Stop();

            if (CurrentFramework is VideoPlayer.VideoPlayer currentVideoPlayer)
                TryPlayVideo();
            else
                AutoPlayTimer.Start();
        }

        private void AutoPlayTimer_Elapsed(object sender, ElapsedEventArgs e)
        {
            if (CurrentFramework is BufferedMediaLoad)
            {
                Application.Current.Dispatcher.Invoke(() => { next(); });
            }
        }

        private void ImgViewer_Loaded(object sender, RoutedEventArgs e)
        {
            #region  initial uxMainPictureStack view
            if (mediaPathList.Count == 0)
            {
                return;
            }

            if (CurrentFramework == null)
            {
                CurrentFramework = CreateMediaFramework(currentIndex);
                uxMainCointainer.Children.Add(CurrentFramework);
                //left
                uxMainCointainer.Children.Insert(0, CreateMediaFramework(currentIndex - 1));
                uxMainCointainer.Children.Insert(0, CreateMediaFramework(currentIndex - 2));
                //right
                uxMainCointainer.Children.Add(CreateMediaFramework(currentIndex + 1));
                uxMainCointainer.Children.Add(CreateMediaFramework(currentIndex + 2));
            }

            //uxMainPictureScroll.ScrollToHorizontalOffset(CurrentFramework);
            UpdateLayout();
            UpdateVideoAutoPauseNPlay();
            SetMainPictureScrollToPos(CurrentFramework.TransformToAncestor(uxMainCointainer).Transform(new Point(0, 0)).X, 0);
            #endregion
        }

        private void MediaViewer_Unloaded(object sender, RoutedEventArgs e)
        {
            //ClearVideoEventHander();
            if (CurrentFramework != null && CurrentFramework is VideoPlayer.VideoPlayer currentVideoPlayer)
            {
                currentVideoPlayer.Stop();
            }
        }

        private void InitStoryboard()
        {
            sbMainScrollOffsetX = new Storyboard();
            DoubleAnimation dbOffset = new DoubleAnimation()
            {
                //Duration = TimeSpan.FromSeconds(0.6),
                EasingFunction = new CubicEase() { EasingMode = EasingMode.EaseOut }
            };
            Storyboard.SetTarget(dbOffset, uxMainScroller);
            Storyboard.SetTargetProperty(dbOffset, new PropertyPath(Utility.ScrollViewerUtilities.HorizontalOffsetProperty));

            sbMainScrollOffsetX.Children.Add(dbOffset);
        }

        private void SbMainScrollOffsetX_Completed(object sender, EventArgs e)
        {
            sbMainScrollOffsetX.Completed -= SbMainScrollOffsetX_Completed;
            RefreshNeighbor();
        }

        private void RefreshNeighbor()
        {
            if (uxMainCointainer.Children.Count == 0)
            {
                //cleared by unloaded
                return;
            }
            int currentFrameworkStackIndex = uxMainCointainer.Children.IndexOf(CurrentFramework);
            //left
            uxMainCointainer.Children.RemoveAt(currentFrameworkStackIndex - 1);
            uxMainCointainer.Children.Insert(currentFrameworkStackIndex - 1, CreateMediaFramework(currentIndex - 1));
            if (currentFrameworkStackIndex - 2 > -1)
            {
                uxMainCointainer.Children.RemoveAt(currentFrameworkStackIndex - 2);
                uxMainCointainer.Children.Insert(currentFrameworkStackIndex - 2, CreateMediaFramework(currentIndex - 2));
            }
            else
            {
                uxMainCointainer.Children.Insert(0, CreateMediaFramework(currentIndex - 2));
            }

            uxMainCointainer.UpdateLayout();
            currentFrameworkStackIndex = uxMainCointainer.Children.IndexOf(CurrentFramework);

            //right
            uxMainCointainer.Children.RemoveAt(currentFrameworkStackIndex + 1);
            uxMainCointainer.Children.Insert(currentFrameworkStackIndex + 1, CreateMediaFramework(currentIndex + 1));

            if (currentFrameworkStackIndex + 2 < uxMainCointainer.Children.Count)
            {
                uxMainCointainer.Children.RemoveAt(currentFrameworkStackIndex + 2);
                uxMainCointainer.Children.Insert(currentFrameworkStackIndex + 2, CreateMediaFramework(currentIndex + 2));
            }
            else
            {
                uxMainCointainer.Children.Insert(0, CreateMediaFramework(currentIndex + 2));
            }

            uxMainCointainer.UpdateLayout();
            SetMainPictureScrollToPos(CurrentFramework.TransformToAncestor(uxMainCointainer).Transform(new Point(0, 0)).X, 0);
            GC.Collect();
        }

        private FrameworkElement CreateMediaFramework(int index)
        {
            while (index < 0)
            {
                index += mediaPathList.Count;
            }
            while (index >= mediaPathList.Count)
            {
                index -= mediaPathList.Count;
            }

            FrameworkElement p;
            if (Utility.GlobalFunction.CheckFileIsImage(mediaPathList[index]))
            {
                //p = new BufferedMediaLoad(mediaPathList[index]) { Height = 1080, Width = 1920 };
                p = new BufferedMediaLoad(mediaPathList[index]) { Height = this.ActualHeight, Width = this.ActualWidth };
            }
            else if (Utility.GlobalFunction.CheckFileIsVideo(mediaPathList[index]))
            {
                //p = new VideoPlayer.VideoPlayer(new Uri(mediaPathList[index]), VideoPlayer.VideoState.stop) { Height = 1080, Width = 1920 };
                VideoPlayer.VideoPlayer vp = new VideoPlayer.VideoPlayer(new Uri(mediaPathList[index]), VideoPlayer.VideoState.stop) { Height = this.ActualHeight, Width = this.ActualWidth };
                vp.SetVolume(VideoVolume);
                vp.OnVideoComplete -= MediaFramework_OnVideoComplete;
                vp.OnVideoComplete += MediaFramework_OnVideoComplete;

                p = vp;
            }
            else
            {
                throw new Exception("<CreateMediaFramework> File format error");
            }
            p.Tag = mediaPathList[index];
            return p;
        }

        private void MediaFramework_OnVideoComplete(object sender, EventArgs e)
        {
            if (!isAutoPlayEnablled)
            {
                return;
            }
            next();
        }

        //private UIElement CreateContainer(string imgPath)
        //{
        //    var item = new Image();
        //    item.Source = Utility.GlobalFunction.GetBitMap(imgPath, 1920, 1080);
        //    var contain = new Grid() { Height = 1080, Width = 1920, Background = new SolidColorBrush(Colors.Gray) };
        //    contain.Children.Add(item);
        //    return contain;
        //}

        private void SetMainPictureScrollToPos(double AniValueX, double duration = 0.4)
        {
            DoubleAnimation db = sbMainScrollOffsetX.Children[0] as DoubleAnimation;

            double currentPosition = uxMainScroller.HorizontalOffset;
            if (currentPosition == AniValueX)
                return;
            //db.From = currentPosition;
            db.To = AniValueX;
            db.Duration = TimeSpan.FromSeconds(duration);
            sbMainScrollOffsetX.Duration = TimeSpan.FromSeconds(duration);

            sbMainScrollOffsetX.Begin();

            AutoPlayTimer.Stop();
            if (CurrentFramework is BufferedMediaLoad && isAutoPlayEnablled)
            {
                AutoPlayTimer.Start();
            }
        }

        private void next()
        {
            ClearVideoEventHander();
            if (NextFramework != null)
            {
                SetMainPictureScrollToPos(NextFramework.TransformToAncestor(uxMainCointainer).Transform(new Point(0, 0)).X, 0.6);

                CurrentFramework = NextFramework;
                currentIndex++;

                AutoPlayTimer.Stop();
                if (CurrentFramework is BufferedMediaLoad && isAutoPlayEnablled)
                {
                    AutoPlayTimer.Start();
                }

                OnCurrentIndexChanged?.Invoke(this, currentIndex);

                EdgeHandle();
            }
        }

        private void previous()
        {
            ClearVideoEventHander();
            if (PreviousFramework != null)
            {
                SetMainPictureScrollToPos(PreviousFramework.TransformToAncestor(uxMainCointainer).Transform(new Point(0, 0)).X, 0.6);
                CurrentFramework = PreviousFramework;
                currentIndex--;
                OnCurrentIndexChanged?.Invoke(this, currentIndex);

                EdgeHandle();
            }
        }

        private async void EdgeHandle()
        {
            await Task.Delay(TimeSpan.FromSeconds(0.6));
            int currentFrameworkStackIndex = uxMainCointainer.Children.IndexOf(CurrentFramework);
            int stackFrameworkCount = uxMainCointainer.Children.Count;
            double currentFrameWorkOffset;

            ClearVideoEventHander();
            //left in
            if (currentFrameworkStackIndex < 2)
            {
                uxMainCointainer.Children.Insert(0, CreateMediaFramework(currentIndex - 2));
            }
            //right in
            if (currentFrameworkStackIndex > (stackFrameworkCount - 1) - 2)
            {
                uxMainCointainer.Children.Add(CreateMediaFramework(currentIndex + 2));
            }
            //left out
            if (currentFrameworkStackIndex > 2)
            {
                //currentFrameworkStackIndex > 3
                uxMainCointainer.Children.RemoveAt(0);
            }
            //right out
            if (currentFrameworkStackIndex < (stackFrameworkCount - 1) - 2)
            {
                uxMainCointainer.Children.RemoveAt(uxMainCointainer.Children.Count - 1);
            }

            try
            {
                uxMainCointainer.UpdateLayout();
                currentFrameWorkOffset = CurrentFramework.TransformToAncestor(uxMainCointainer).Transform(new Point(0, 0)).X;
                SetMainPictureScrollToPos(currentFrameWorkOffset, 0);
                //video check
                UpdateVideoAutoPauseNPlay();
            }
            catch
            {
                return;
            }
            //resetAutoPlayTimer();
            GC.Collect();
        }

        private void ClearVideoEventHander()
        {
            foreach (UIElement element in uxMainCointainer.Children)
            {
                if (element is VideoPlayer.VideoPlayer videoPlayer)
                {
                    videoPlayer.OnVideoStateChanged -= VideoPlayer_OnVideoStateChanged;
                    videoPlayer.OnVideoComplete -= MediaFramework_OnVideoComplete;
                }
            }
        }

        private void UpdateVideoAutoPauseNPlay()
        {
            if (PreviousFramework != null && PreviousFramework is VideoPlayer.VideoPlayer preVideoPlayer)
            {
                preVideoPlayer.OnVideoStateChanged -= VideoPlayer_OnVideoStateChanged;
                preVideoPlayer.Pause();
            }
            if (NextFramework != null && NextFramework is VideoPlayer.VideoPlayer nextVideoPlayer)
            {
                nextVideoPlayer.OnVideoStateChanged -= VideoPlayer_OnVideoStateChanged;
                nextVideoPlayer.Pause();
            }
            if (CurrentFramework != null && CurrentFramework is VideoPlayer.VideoPlayer currentVideoPlayer)
            {
                currentVideoPlayer.Play();
                currentVideoPlayer.OnVideoStateChanged -= VideoPlayer_OnVideoStateChanged;
                currentVideoPlayer.OnVideoStateChanged += VideoPlayer_OnVideoStateChanged;

                currentVideoPlayer.OnVideoComplete -= MediaFramework_OnVideoComplete;
                currentVideoPlayer.OnVideoComplete += MediaFramework_OnVideoComplete;
            }
        }

        private void VideoPlayer_OnVideoStateChanged(object sender, VideoPlayer.VideoState e)
        {
            OnVideoStateChanged?.Invoke(this, e);
        }

        #region UI element event
        private double cumulativeDelta = 0;
        public void InformManipulationDelta(ManipulationDeltaEventArgs e)
        {
            cumulativeDelta = e.CumulativeManipulation.Translation.X;
            if (Math.Abs(cumulativeDelta) < ActualWidth / 2)
                ScrollViewer_ManipulationDelta(null, e);
        }

        public void InformManipulationCompleted(ManipulationCompletedEventArgs e)
        {
            uxMainScroller_ManipulationCompleted(null, e);
            cumulativeDelta = 0;
        }

        private void uxMainScroller_ManipulationStarting(object sender, ManipulationStartingEventArgs e)
        {

        }

        int deltatimetamp = 0;
        private void ScrollViewer_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
        {
            //uxMainScroller.ScrollToHorizontalOffset(uxMainScroller.HorizontalOffset - e.DeltaManipulation.Translation.X);

            //uxMainPictureScroll.ScrollToHorizontalOffset(uxMainPictureScroll.HorizontalOffset - e.DeltaManipulation.Translation.X);
            if (e.Manipulators.Count() == 1 && e.Timestamp != deltatimetamp)
            {
                SetMainPictureScrollToPos(uxMainScroller.HorizontalOffset - e.DeltaManipulation.Translation.X, 0);
                deltatimetamp = e.Timestamp;
            }
        }

        private void uxMainScroller_ManipulationInertiaStarting(object sender, ManipulationInertiaStartingEventArgs e)
        {

        }

        private void uxMainScroller_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
        {
            double currentFrameWorkOffset = CurrentFramework.TransformToAncestor(uxMainCointainer).Transform(new Point(0, 0)).X;

            if (uxMainScroller.HorizontalOffset < currentFrameWorkOffset - 200 || e.FinalVelocities.LinearVelocity.X > slipSpeedMin)
            {
                previous();
            }
            else if (uxMainScroller.HorizontalOffset > currentFrameWorkOffset + 200 || e.FinalVelocities.LinearVelocity.X < -slipSpeedMin)
            {
                next();
            }
            else
            {
                SetMainPictureScrollToPos(currentFrameWorkOffset);
            }
        }

        #endregion
    }
}
