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.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using VIZ.Framework.Core;
using VIZ.Framework.Domain;
using log4net;

namespace VIZ.Framework.Common
{
    /// <summary>
    /// 视频播放器时间条
    /// </summary>
    [TemplatePart(Name = nameof(PART_Slider), Type = typeof(Slider))]
    [TemplatePart(Name = nameof(PART_Copy), Type = typeof(FrameworkElement))]
    public class VideoTimeBar : Control, IDisposable
    {
        static VideoTimeBar()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(VideoTimeBar), new FrameworkPropertyMetadata(typeof(VideoTimeBar)));
        }

        /// <summary>
        /// 日志
        /// </summary>
        private static ILog log = LogManager.GetLogger(typeof(VideoTimeBar));

        /// <summary>
        /// TimeSpan格式化字符串
        /// </summary>
        private static readonly string TIME_SPAN_FORMAT = "hh\\:mm\\:ss";

        /// <summary>
        /// 视频播放器时间条
        /// </summary>
        public VideoTimeBar()
        {

        }

        // ======================================================================================
        // === Field ===
        // ======================================================================================

        /// <summary>
        /// 进度条
        /// </summary>
        private Slider PART_Slider;

        /// <summary>
        /// 拷贝控件
        /// </summary>
        private FrameworkElement PART_Copy;

        /// <summary>
        /// 是否正在等待手动改变值
        /// </summary>
        private bool isWaitManualValueChanging;

        /// <summary>
        /// 手动改变值时触发
        /// </summary>
        public event EventHandler<VideoTimeBarValueChangedEventArgs> TimeBarManualValueChanged;

        // ======================================================================================
        // === Property ===
        // ======================================================================================

        #region MaxTime -- 最大时间

        /// <summary>
        /// 最大时间
        /// </summary>
        public TimeSpan MaxTime
        {
            get { return (TimeSpan)GetValue(MaxTimeProperty); }
            set { SetValue(MaxTimeProperty, value); }
        }

        /// <summary>
        /// Using a DependencyProperty as the backing store for MaxTime.  This enables animation, styling, binding, etc...
        /// </summary>
        public static readonly DependencyProperty MaxTimeProperty =
            DependencyProperty.Register("MaxTime", typeof(TimeSpan), typeof(VideoTimeBar), new PropertyMetadata(TimeSpan.Zero, new PropertyChangedCallback((s, e) =>
            {
                (s as VideoTimeBar).TryUpdateSliderMaxValue();
            })));

        #endregion

        #region Time -- 时间

        /// <summary>
        /// 时间
        /// </summary>
        public TimeSpan Time
        {
            get { return (TimeSpan)GetValue(TimeProperty); }
            set { SetValue(TimeProperty, value); }
        }

        /// <summary>
        /// Using a DependencyProperty as the backing store for Time.  This enables animation, styling, binding, etc...
        /// </summary>
        public static readonly DependencyProperty TimeProperty =
            DependencyProperty.Register("Time", typeof(TimeSpan), typeof(VideoTimeBar), new PropertyMetadata(TimeSpan.Zero, new PropertyChangedCallback((s, e) =>
            {
                (s as VideoTimeBar).TryUpdateSliderValue();
            })));

        #endregion

        #region TimeString -- 时间字符串

        /// <summary>
        /// 时间字符串
        /// </summary>
        public string TimeString
        {
            get { return (string)GetValue(TimeStringProperty); }
            set { SetValue(TimeStringProperty, value); }
        }

        /// <summary>
        /// Using a DependencyProperty as the backing store for TimeString.  This enables animation, styling, binding, etc...
        /// </summary>
        public static readonly DependencyProperty TimeStringProperty =
            DependencyProperty.Register("TimeString", typeof(string), typeof(VideoTimeBar), new PropertyMetadata(TimeSpan.Zero.ToString(TIME_SPAN_FORMAT)));

        #endregion

        // ======================================================================================
        // === Public Function ===
        // ======================================================================================

        /// <summary>
        /// 销毁
        /// </summary>
        public void Dispose()
        {
            ApplicationDomain.LoopManager.UnRegister($"VideoTimeBar_{this.GetHashCode()}");
        }

        // ======================================================================================
        // === Override Function ===
        // ======================================================================================

        /// <summary>
        /// 应用模板
        /// </summary>
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            this.PART_Slider = this.Template.FindName(nameof(this.PART_Slider), this) as Slider;
            this.PART_Slider.Minimum = 0d;

            this.PART_Slider.PreviewMouseLeftButtonDown -= PART_Slider_PreviewMouseLeftButtonDown;
            this.PART_Slider.PreviewMouseLeftButtonDown += PART_Slider_PreviewMouseLeftButtonDown;
            this.PART_Slider.PreviewMouseLeftButtonUp -= PART_Slider_PreviewMouseLeftButtonUp;
            this.PART_Slider.PreviewMouseLeftButtonUp += PART_Slider_PreviewMouseLeftButtonUp;
            this.PART_Slider.ValueChanged -= PART_Slider_ValueChanged;
            this.PART_Slider.ValueChanged += PART_Slider_ValueChanged;

            this.PART_Copy = this.Template.FindName(nameof(this.PART_Copy), this) as FrameworkElement;
            this.PART_Copy.PreviewMouseLeftButtonUp -= PART_Copy_PreviewMouseLeftButtonUp;
            this.PART_Copy.PreviewMouseLeftButtonUp += PART_Copy_PreviewMouseLeftButtonUp;
        }

        // ======================================================================================
        // === Private Function ===
        // ======================================================================================

        /// <summary>
        /// 拷贝
        /// </summary>
        private void PART_Copy_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            Clipboard.SetText(this.TimeString);
        }

        /// <summary>
        /// 鼠标左键按下
        /// </summary>
        private void PART_Slider_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            this.isWaitManualValueChanging = true;
        }

        /// <summary>
        /// 鼠标释放
        /// </summary>
        private void PART_Slider_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            if (!this.isWaitManualValueChanging)
                return;

            VideoTimeBarValueChangedEventArgs args = new VideoTimeBarValueChangedEventArgs();
            args.MaxTime = this.MaxTime;
            args.Time = TimeSpan.FromSeconds(this.PART_Slider.Value);

            this.TimeBarManualValueChanged?.Invoke(this, args);

            this.isWaitManualValueChanging = false;
        }

        /// <summary>
        /// 进度值改变
        /// </summary>
        private void PART_Slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            if (!this.isWaitManualValueChanging)
                return;

            this.TimeString = TimeSpan.FromSeconds(this.PART_Slider.Value).ToString(TIME_SPAN_FORMAT);
            this.SetCurrentValue(TimeProperty, TimeSpan.FromSeconds(this.PART_Slider.Value));
        }

        /// <summary>
        /// 尝试更新进度值
        /// </summary>
        private void TryUpdateSliderValue()
        {
            WPFHelper.BeginInvoke(() =>
            {
                if (this.isWaitManualValueChanging)
                    return;

                this.PART_Slider.Value = this.Time.TotalSeconds;
                this.TimeString = this.Time.ToString(TIME_SPAN_FORMAT);
            });
        }

        /// <summary>
        /// 尝试更新进度最大值
        /// </summary>
        private void TryUpdateSliderMaxValue()
        {
            this.PART_Slider.Maximum = this.MaxTime.TotalSeconds;
        }
    }
}
