using FoxTube.Controls;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Windows.ApplicationModel.Resources;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using YoutubeExplode.Models.ClosedCaptions;
using YoutubeExplode.Models.MediaStreams;

namespace FoxTube
{
    public delegate void QualityChangedEventHandler(object sender, MediaStreamInfo requestedQuality, MediaStreamInfoSet list);
    public delegate void MinimodeChangedEventHandler(object sender, bool isOn);

    /// <summary>
    /// Custom controls for media player. MARKUP IS IN **Themes/Generic.xaml**!!!
    /// </summary>
    public sealed class PlayerControls : MediaTransportControls
    {
        public event RoutedEventHandler CloseRequested;
        public event MinimodeChangedEventHandler MiniModeChanged;
        public event RoutedEventHandler NextRequested;

        public event QualityChangedEventHandler QualityChanged;

        public MediaElement Player;

        public IReadOnlyList<ClosedCaptionTrackInfo> ClosedCaptions { get; set; }
        public MediaStreamInfoSet MediaStreams { get; set; }

        Queue<Action> queue = new Queue<Action>();
        bool isReady = false;

        public PlayerControls()
        {
            DefaultStyleKey = typeof(PlayerControls);
        }

        protected override void OnApplyTemplate()
        {
            isReady = true;

            (GetTemplateChild("close") as Button).Click += Close_Click;
            (GetTemplateChild("compactClose") as Button).Click += Close_Click;

            (GetTemplateChild("minimize") as Button).Click += Minimize_Click;
            (GetTemplateChild("maximize") as Button).Click += Minimize_Click;

            (GetTemplateChild("CompactOverlayButton") as Button).Click += CompactOverlay_Click;

            (GetTemplateChild("qualitySelector") as ComboBox).SelectionChanged += QualitySelector_SelectionChanged;

            (GetTemplateChild("ccSwitch") as ToggleSwitch).Toggled += CcSwitch_Toggled;
            (GetTemplateChild("ccSelector") as ComboBox).SelectionChanged += CcSelector_SelectionChanged;

            (GetTemplateChild("next") as Button).Click += (s, e) => NextRequested.Invoke(s, e);

            (GetTemplateChild("AudioMuteButton") as Button).Click += Mute_Click;
            (GetTemplateChild("VolumeSlider") as Slider).ValueChanged += Volume_ValueChanged;

            (GetTemplateChild("ProgressSlider") as Slider).ValueChanged += ProgressSlider_ValueChanged;

            if (queue.Count > 0)
                foreach (Action i in queue)
                    i();
            
            base.OnApplyTemplate();
        }

        private void Minimize_Click(object sender, RoutedEventArgs e)
        {
            if (sender == (GetTemplateChild("minimize") as Button))
            {
                MiniModeChanged.Invoke(this, true);
                SetMinimized();
            }
            else
            {
                MiniModeChanged.Invoke(this, false);
                SetNormal();
            }
        }

        private void ProgressSlider_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
        {
            (GetTemplateChild("compactSeek") as ProgressBar).Value = e.NewValue;
        }

        private void Mute_Click(object sender, RoutedEventArgs e)
        {
            if (((GetTemplateChild("AudioMuteButton") as Button).Content as FontIcon).Glyph == "\xE74F")
                Volume_ValueChanged(this, null);
            else
                ((GetTemplateChild("AudioMuteButton") as Button).Content as FontIcon).Glyph = ((GetTemplateChild("volume") as Button).Content as FontIcon).Glyph = "\xE74F";
        }

        private void Volume_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
        {
            double v = (GetTemplateChild("VolumeSlider") as Slider).Value;
            if (v == 0)
                ((GetTemplateChild("AudioMuteButton") as Button).Content as FontIcon).Glyph = ((GetTemplateChild("volume") as Button).Content as FontIcon).Glyph = "\xE74F";
            else if (v <= 25 && v > 0)
                ((GetTemplateChild("AudioMuteButton") as Button).Content as FontIcon).Glyph = ((GetTemplateChild("volume") as Button).Content as FontIcon).Glyph = "\xE992";
            else if (v <= 50 && v > 25)
                ((GetTemplateChild("AudioMuteButton") as Button).Content as FontIcon).Glyph = ((GetTemplateChild("volume") as Button).Content as FontIcon).Glyph = "\xE993";
            else if (v <= 75 && v > 50)
                ((GetTemplateChild("AudioMuteButton") as Button).Content as FontIcon).Glyph = ((GetTemplateChild("volume") as Button).Content as FontIcon).Glyph = "\xE994";
            else if (v > 75)
                ((GetTemplateChild("AudioMuteButton") as Button).Content as FontIcon).Glyph = ((GetTemplateChild("volume") as Button).Content as FontIcon).Glyph = "\xE995";
        }

        private void CcSelector_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            CcSwitch_Toggled((GetTemplateChild("ccSwitch") as ToggleSwitch), null);
        }

        private void CcSwitch_Toggled(object sender, RoutedEventArgs e)
        {
            if((GetTemplateChild("captions") as LiveCaptions).Player == null)
                (GetTemplateChild("captions") as LiveCaptions).Player = Player;

            if ((sender as ToggleSwitch).IsOn)
                (GetTemplateChild("captions") as LiveCaptions).Initialize(((GetTemplateChild("ccSelector") as ComboBox).SelectedItem as ComboBoxItem).Tag as ClosedCaptionTrackInfo);
            else
                (GetTemplateChild("captions") as LiveCaptions).Close();
        }

        private void QualitySelector_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            SettingsStorage.RememberedQuality = e.AddedItems[0] as string;
            MediaStreamInfo item = MediaStreams.Muxed.Find(i => i.VideoQualityLabel == e.AddedItems[0] as string);
            if (item == null)
                item = MediaStreams.Video.Find(i => i.VideoQualityLabel == e.AddedItems[0] as string);

            QualityChanged?.Invoke(sender, item, MediaStreams);
        }

        private void CompactOverlay_Click(object sender, RoutedEventArgs e)
        {
            if((sender as Button).Margin.Top > 0)
            {
                Button btnCompact = sender as Button;
                (GetTemplateChild("center") as Grid).Children.Remove(btnCompact);
                (GetTemplateChild("headerToolbar") as StackPanel).Children.Add(btnCompact);

                btnCompact.Margin = new Thickness(0);
                (btnCompact.Content as FontIcon).Glyph = "\xE2B3";

                SetNormal();
            }
            else
                SetCompactView();
        }

        private void Close_Click(object sender, RoutedEventArgs e)
        {
            CloseRequested?.Invoke(sender, e);
        }

        public void SetCompactView()
        {
            Button btn = GetTemplateChild("CompactOverlayButton") as Button;
            (GetTemplateChild("headerToolbar") as StackPanel).Children.Remove(btn);
            (GetTemplateChild("center") as Grid).Children.Add(btn);

            btn.Margin = new Thickness(0, 32, 0, 0);
            (btn.Content as FontIcon).Glyph = "\xE2B4";

            Button btnPlay = GetTemplateChild("PlayPauseButton") as Button;
            (GetTemplateChild("leftStack") as StackPanel).Children.Remove(btnPlay);
            (GetTemplateChild("centralStack") as StackPanel).Children.Add(btnPlay);

            Button btnFwd = GetTemplateChild("SkipForwardButton") as Button;
            (GetTemplateChild("rightStack") as StackPanel).Children.Remove(btnFwd);
            (GetTemplateChild("centralStack") as StackPanel).Children.Insert(1, btnFwd);

            Button btnBwd = GetTemplateChild("SkipBackwardButton") as Button;
            (GetTemplateChild("rightStack") as StackPanel).Children.Remove(btnBwd);
            (GetTemplateChild("centralStack") as StackPanel).Children.Insert(0, btnBwd);

            (GetTemplateChild("header") as Grid).Visibility = Visibility.Collapsed;
            (GetTemplateChild("centerBgr") as Grid).Visibility = Visibility.Visible;
            (GetTemplateChild("center") as Grid).Visibility = Visibility.Visible;
            (GetTemplateChild("footer") as Grid).Visibility = Visibility.Collapsed;

            (GetTemplateChild("maximize") as Button).Visibility = Visibility.Collapsed;
            (GetTemplateChild("compactClose") as Button).Visibility = Visibility.Collapsed;

            (GetTemplateChild("captions") as LiveCaptions).Size = 15;
        }

        public void SetMinimized()
        {
            Button btnPlay = GetTemplateChild("PlayPauseButton") as Button;
            (GetTemplateChild("leftStack") as StackPanel).Children.Remove(btnPlay);
            (GetTemplateChild("centralStack") as StackPanel).Children.Add(btnPlay);

            Button btnFwd = GetTemplateChild("SkipForwardButton") as Button;
            (GetTemplateChild("rightStack") as StackPanel).Children.Remove(btnFwd);
            (GetTemplateChild("centralStack") as StackPanel).Children.Insert(1, btnFwd);

            Button btnBwd = GetTemplateChild("SkipBackwardButton") as Button;
            (GetTemplateChild("rightStack") as StackPanel).Children.Remove(btnBwd);
            (GetTemplateChild("centralStack") as StackPanel).Children.Insert(0, btnBwd);

            (GetTemplateChild("header") as Grid).Visibility = Visibility.Collapsed;
            (GetTemplateChild("centerBgr") as Grid).Visibility = Visibility.Visible;
            (GetTemplateChild("center") as Grid).Visibility = Visibility.Visible;
            (GetTemplateChild("footer") as Grid).Visibility = Visibility.Collapsed;

            (GetTemplateChild("compactClose") as Button).Visibility = Visibility.Visible;
            (GetTemplateChild("maximize") as Button).Visibility = Visibility.Visible;

            (GetTemplateChild("captions") as LiveCaptions).Size = 15;
        }

        public void SetNormal()
        {
            Button btnPlay = GetTemplateChild("PlayPauseButton") as Button;
            (GetTemplateChild("centralStack") as StackPanel).Children.Remove(btnPlay);
            (GetTemplateChild("leftStack") as StackPanel).Children.Insert(0, btnPlay);

            Button btnFwd = GetTemplateChild("SkipForwardButton") as Button;
            (GetTemplateChild("centralStack") as StackPanel).Children.Remove(btnFwd);
            (GetTemplateChild("rightStack") as StackPanel).Children.Insert(0, btnFwd);

            Button btnBwd = GetTemplateChild("SkipBackwardButton") as Button;
            (GetTemplateChild("centralStack") as StackPanel).Children.Remove(btnBwd);
            (GetTemplateChild("rightStack") as StackPanel).Children.Insert(0, btnBwd);

            (GetTemplateChild("header") as Grid).Visibility = Visibility.Visible;
            (GetTemplateChild("centerBgr") as Grid).Visibility = Visibility.Collapsed;
            (GetTemplateChild("center") as Grid).Visibility = Visibility.Collapsed;
            (GetTemplateChild("footer") as Grid).Visibility = Visibility.Visible;

            (GetTemplateChild("captions") as LiveCaptions).Size = 24;
        }

        public void SetMeta(string title, string channel)
        {
            if (!isReady)
            {
                queue.Enqueue(() => SetMeta(title, channel));
                return;
            }
            (GetTemplateChild("title") as TextBlock).Text = title;
            (GetTemplateChild("author") as TextBlock).Text = channel;
        }

        public void SetCaptions(IReadOnlyList<ClosedCaptionTrackInfo> list)
        {
            if (!isReady)
            {
                queue.Enqueue(() => SetCaptions(list));
                return;
            }

            ClosedCaptions = list;

            if (list.Count > 0)
            {
                foreach(ClosedCaptionTrackInfo i in list)
                    (GetTemplateChild("ccSelector") as ComboBox).Items.Add(new ComboBoxItem()
                    {
                        Content = string.Format("{0} {1}", CultureInfo.GetCultureInfo(i.Language.Code).DisplayName, i.IsAutoGenerated ? ResourceLoader.GetForCurrentView("VideoPage").GetString("/VideoPage/generatedCaption") : ""),
                        Tag = i
                    });

                ClosedCaptionTrackInfo item = list.Find(i => SettingsStorage.RelevanceLanguage.Contains(i.Language.Code)) ?? list.Find(i => "en-US".Contains(i.Language.Code));
                if (item == null)
                    item = list.First();

                (GetTemplateChild("ccSelector") as ComboBox).SelectedItem = (GetTemplateChild("ccSelector") as ComboBox).Items.Find(i => (i as ComboBoxItem).Tag == item);
            }
            else
                (GetTemplateChild("cc") as Button).Visibility = Visibility.Collapsed;
        }

        public void SetQualities(MediaStreamInfoSet list)
        {
            if (!isReady)
            {
                queue.Enqueue(() => SetQualities(list));
                return;
            }

            MediaStreams = list;

            List<VideoQuality> q = list.GetAllVideoQualities().ToList();
            q.Sort();
            q.Reverse();
            List<string> labels = new List<string>();
            q.ForEach(i => labels.Add(i.GetVideoQualityLabel()));
            (GetTemplateChild("qualitySelector") as ComboBox).ItemsSource = labels;

            string s = SettingsStorage.VideoQuality == "remember" ? SettingsStorage.RememberedQuality : SettingsStorage.VideoQuality;

            if (labels.Contains(s))
                (GetTemplateChild("qualitySelector") as ComboBox).SelectedItem = s;
            else
                (GetTemplateChild("qualitySelector") as ComboBox).SelectedIndex = 0;
        }

        public void SetStream(string url)
        {
            if (!isReady)
            {
                queue.Enqueue(() => SetStream(url));
                return;
            }

            // TODO: Set up stream UI
        }
    }
}
