using System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Google.Apis.YouTube.v3;
using Google.Apis.YouTube.v3.Data;
using Windows.UI.Xaml.Media.Imaging;
using Windows.System;
using Windows.ApplicationModel.DataTransfer;
using Windows.ApplicationModel.Resources;
using Microsoft.AppCenter.Analytics;
using System.Collections.Generic;
using YoutubeExplode;
using Windows.UI.Popups;
using YoutubeExplode.Models.MediaStreams;
using Windows.Foundation;
using FoxTube.Pages;
using Windows.Networking.Connectivity;
using Microsoft.Toolkit.Uwp.UI.Controls;

namespace FoxTube.Controls
{
    /// <summary>
    /// Video item card
    /// </summary>
    public sealed partial class VideoCard : UserControl
    {
        ResourceLoader resources = ResourceLoader.GetForCurrentView("Cards");

        public string playlistId;
        Video item;
        HistoryItem history;

        public VideoCard(string id, string playlist = null)
        {
            InitializeComponent();
            Initialize(id, playlist);
        }


        public VideoCard(Video meta, string playlist = null)
        {
            InitializeComponent();
            item = meta;
            playlistId = playlist;
            LoadMeta();
        }

        public async void Initialize(string id, string playlist = null)
        {
            try
            {
                playlistId = playlist;
                delete.Visibility = string.IsNullOrWhiteSpace(playlistId) ? Visibility.Collapsed : Visibility.Visible;

                VideosResource.ListRequest request = SecretsVault.Service.Videos.List("snippet,contentDetails,statistics,liveStreamingDetails");
                request.Id = id;
                request.Hl = SettingsStorage.RelevanceLanguage;
                item = (await request.ExecuteAsync()).Items[0];

                title.Text = item.Snippet.Localized.Title;
                channelName.Text = item.Snippet.ChannelTitle;

                if (item.Snippet.Title == "Deleted video")
                {
                    ContextFlyout = null;
                    show.Begin();
                    return;
                }

                if (item.Snippet.LiveBroadcastContent == "live")
                {
                    views.Text = $"{item.LiveStreamingDetails.ConcurrentViewers:0,0} {resources.GetString("/Cards/viewers")}";
                    if (item.LiveStreamingDetails.ScheduledStartTime.HasValue && item.LiveStreamingDetails.ScheduledEndTime.HasValue)
                        info.Text = $"{item.LiveStreamingDetails.ScheduledEndTime - item.LiveStreamingDetails.ActualStartTime} | {Methods.GetAgo(item.LiveStreamingDetails.ActualStartTime.Value)}";
                    else
                        info.Text = Methods.GetAgo(item.LiveStreamingDetails.ActualStartTime.Value);
                    liveTag.Visibility = Visibility.Visible;
                    download.Visibility = Visibility.Collapsed;
                }
                else if (item.Snippet.LiveBroadcastContent == "upcoming")
                {
                    views.Text = "";
                    if (item.LiveStreamingDetails.ScheduledStartTime.HasValue && item.LiveStreamingDetails.ScheduledEndTime.HasValue)
                        info.Text = $"{item.LiveStreamingDetails.ScheduledEndTime - item.LiveStreamingDetails.ScheduledStartTime} | {item.LiveStreamingDetails.ScheduledStartTime}";
                    else
                        info.Text = $"{Methods.GetAgo(item.Snippet.PublishedAt.Value)}";
                    liveTag.Visibility = Visibility.Visible;

                    if (item.LiveStreamingDetails.ScheduledStartTime.HasValue)
                        liveContent.Text = resources.GetString("/Cards/goesLive") + (item.LiveStreamingDetails.ScheduledStartTime.Value > DateTime.Now ? " " : " -") + (item.LiveStreamingDetails.ScheduledStartTime.Value - DateTime.Now).ToString(@"hh\:mm\:ss");
                    else liveContent.Text = resources.GetString("/Cards/upcoming");
                    download.Visibility = Visibility.Collapsed;
                }
                else
                {
                    views.Text = $"{item.Statistics.ViewCount:0,0} {resources.GetString("/Cards/views")}";
                    info.Text = $"{item.ContentDetails.Duration.GetDuration()} | {Methods.GetAgo(item.Snippet.PublishedAt.Value)}";
                    LoadDownloads();
                }
                LoadAddTo();

                var channelRequest = SecretsVault.Service.Channels.List("snippet");
                channelRequest.Id = item.Snippet.ChannelId;

                try
                {
                    thumbnail.Source = new BitmapImage(item.Snippet.Thumbnails.Medium.Url.ToUri());
                    avatar.ProfilePicture = new BitmapImage((await channelRequest.ExecuteAsync()).Items[0].Snippet.Thumbnails.Medium.Url.ToUri()) { DecodePixelHeight = 46, DecodePixelWidth = 46 };
                    //avatar.ProfilePicture = new BitmapImage((await new YoutubeClient().GetChannelAsync(item.Snippet.ChannelId)).LogoUrl.ToUri()) { DecodePixelWidth = 46, DecodePixelHeight = 46 };
                }
                catch { }

                if (SecretsVault.History.Contains(item.Id))
                    watched.Visibility = Visibility.Visible;
                if (HistorySet.Items.Exists(i => i.Id == item.Id))
                {
                    history = HistorySet.Items.Find(i => i.Id == item.Id);
                    watched.Visibility = Visibility.Visible;
                    leftOn.Value = 100 * HistorySet.Items.Find(i => i.Id == item.Id).LeftOn.TotalSeconds / Methods.GetDuration(item.ContentDetails.Duration).TotalSeconds;
                }

                show.Begin();
            }
            catch (Exception e)
            {
                (Parent as AdaptiveGridView)?.Items.Remove(this);
                Visibility = Visibility.Collapsed;
                if (item == null)
                    return;
                Analytics.TrackEvent("VideoCard loading failed", new Dictionary<string, string>()
                {
                    { "Exception", e.GetType().ToString() },
                    { "Message", e.Message },
                    { "Video ID", item.Id },
                    { "StackTrace", e.StackTrace }
                });
            }
        }

        async void LoadDownloads()
        {
            try
            {
                MediaStreamInfoSet infoSet = await new YoutubeClient().GetVideoMediaStreamInfosAsync(item.Id);
                foreach (MuxedStreamInfo i in infoSet.Muxed)
                {
                    MenuFlyoutItem menuItem = new MenuFlyoutItem()
                    {
                        Text = i.VideoQualityLabel,
                        Tag = new object[] { i, i.VideoQualityLabel }
                    };
                    menuItem.Click += downloadItemSelected;
                    download.Items.Add(menuItem);
                }

                MenuFlyoutItem audioItem = new MenuFlyoutItem()
                {
                    Text = resources.GetString("/VideoPage/audio"),
                    Tag = new object[] { infoSet.Audio[0], resources.GetString("/Cards/audioOnly") }
                };
                audioItem.Click += downloadItemSelected;
                download.Items.Add(audioItem);
            }
            catch
            {
                download.Visibility = Visibility.Collapsed;
            }
        }

        private void downloadItemSelected(object sender, RoutedEventArgs e)
        {
            DownloadAgent.Add(((sender as MenuFlyoutItem).Tag as object[])[0] as MediaStreamInfo, item, ((sender as MenuFlyoutItem).Tag as object[])[1] as string);
        }

        public async void LoadMeta()
        {
            title.Text = item.Snippet.Title;
            channelName.Text = item.Snippet.ChannelTitle;

            if (item.Snippet.Title == "Deleted video")
            {
                ContextFlyout = null;
                show.Begin();
                return;
            }

            if (item.Snippet.LiveBroadcastContent == "live")
            {
                views.Text = $"{item.LiveStreamingDetails.ConcurrentViewers:0,0} {resources.GetString("/Cards/viewers")}";
                if (item.LiveStreamingDetails.ScheduledStartTime.HasValue && item.LiveStreamingDetails.ScheduledEndTime.HasValue)
                    info.Text = $"{item.LiveStreamingDetails.ScheduledEndTime - item.LiveStreamingDetails.ActualStartTime} | {Methods.GetAgo(item.LiveStreamingDetails.ActualStartTime.Value)}";
                else
                    info.Text = Methods.GetAgo(item.LiveStreamingDetails.ActualStartTime.Value);
                liveTag.Visibility = Visibility.Visible;
            }
            else if (item.Snippet.LiveBroadcastContent == "upcoming")
            {
                views.Text = "";
                if (item.LiveStreamingDetails.ScheduledStartTime.HasValue && item.LiveStreamingDetails.ScheduledEndTime.HasValue)
                    info.Text = $"{item.LiveStreamingDetails.ScheduledEndTime - item.LiveStreamingDetails.ScheduledStartTime} | {item.LiveStreamingDetails.ScheduledStartTime}";
                else
                    info.Text = $"{Methods.GetAgo(item.Snippet.PublishedAt.Value)}";
                liveTag.Visibility = Visibility.Visible;

                if (item.LiveStreamingDetails.ScheduledStartTime.HasValue)
                    liveContent.Text = $"{resources.GetString("/Cards/goesLive")} {item.LiveStreamingDetails.ScheduledStartTime - DateTime.Now}";
                else liveContent.Text = resources.GetString("/Cards/upcoming");
            }
            else
            {
                views.Text = $"{item.Statistics.ViewCount:0,0} {resources.GetString("/Cards/views")}";
                info.Text = $"{item.ContentDetails.Duration.GetDuration()} | {Methods.GetAgo(item.Snippet.PublishedAt.Value)}";
            }

            var channelRequest = SecretsVault.Service.Channels.List("snippet");
            channelRequest.Id = item.Snippet.ChannelId;

            try
            {
                thumbnail.Source = new BitmapImage(item.Snippet.Thumbnails.Medium.Url.ToUri());
                avatar.ProfilePicture = new BitmapImage((await channelRequest.ExecuteAsync()).Items[0].Snippet.Thumbnails.Medium.Url.ToUri()) { DecodePixelHeight = 46, DecodePixelWidth = 46 };
                //avatar.ProfilePicture = new BitmapImage((await new YoutubeClient().GetChannelAsync(item.Snippet.ChannelId)).LogoUrl.ToUri()) { DecodePixelWidth = 46, DecodePixelHeight = 46 };
            }
            catch { }

            if (SecretsVault.History.Contains(item.Id))
                watched.Visibility = Visibility.Visible;
            if (HistorySet.Items.Exists(i => i.Id == item.Id))
                leftOn.Value = 100 * HistorySet.Items.Find(i => i.Id == item.Id).LeftOn.TotalSeconds / Methods.GetDuration(item.ContentDetails.Duration).TotalSeconds;

            show.Begin();
        }

        public async void Button_Click(object sender, RoutedEventArgs e)
        {
            if (item.ContentDetails.ContentRating != null)
            {
                if (SecretsVault.IsAuthorized)
                {
                    if (SettingsStorage.Mature == MatureState.Blocked)
                    {
                        MessageDialog dialog = new MessageDialog(resources.GetString("/VideoPage/matureText"), resources.GetString("/VideoPage/wantContinue"));
                        dialog.Commands.Add(new UICommand(resources.GetString("/VideoPage/yes"), null, true));
                        dialog.Commands.Add(new UICommand(resources.GetString("/VideoPage/always"), (command) => SettingsStorage.Mature = MatureState.Allowed, true));
                        dialog.Commands.Add(new UICommand(resources.GetString("/VideoPage/no"), null, false));

                        dialog.CancelCommandIndex = 2;
                        dialog.DefaultCommandIndex = 0;

                        if (!(bool)(await dialog.ShowAsync()).Id)
                            return;
                    }
                }
                else
                {
                    MessageDialog dialog = new MessageDialog(resources.GetString("/VideoPage/matureText"), resources.GetString("/VideoPage/signRequired"));
                    dialog.Commands.Add(new UICommand(resources.GetString("/VideoPage/signin"), (command) => SecretsVault.Authorize()));
                    dialog.Commands.Add(new UICommand(resources.GetString("/VideoPage/cancel")));

                    dialog.CancelCommandIndex = 1;
                    dialog.DefaultCommandIndex = 0;

                    await dialog.ShowAsync();
                    return;
                }
            }

            ConnectionCost connection = NetworkInformation.GetInternetConnectionProfile().GetConnectionCost();
            if (SettingsStorage.CheckConnection && (connection.NetworkCostType == NetworkCostType.Fixed || connection.NetworkCostType == NetworkCostType.Variable))
            {
                MessageDialog dialog = new MessageDialog(resources.GetString("/Main/metered"))
                {
                    DefaultCommandIndex = 2,
                    CancelCommandIndex = 1
                };
                dialog.Commands.Add(new UICommand(resources.GetString("/Main/yes"), null, false));
                dialog.Commands.Add(new UICommand(resources.GetString("/Main/no"), null, true));
                if(SecretsVault.IsAuthorized)
                    dialog.Commands.Add(new UICommand(resources.GetString("/Main/metered"), async (command) => 
                    {
                        try
                        {
                            PlaylistItem playlistItem = new PlaylistItem()
                            {
                                Snippet = new PlaylistItemSnippet()
                                {
                                    ResourceId = new ResourceId()
                                    {
                                        Kind = "youtube#video",
                                        VideoId = item.Id
                                    },
                                    PlaylistId = "WL"
                                }
                            };

                            await SecretsVault.Service.PlaylistItems.Insert(playlistItem, "snippet").ExecuteAsync();
                        }
                        catch { }
                    }, true));

                if ((bool)(await dialog.ShowAsync()).Id)
                    return;
            }

            Methods.MainPage.GoToVideo(item.Id, playlistId == "HL" ? null : playlistId, ((FrameworkElement)sender).Name == "incognito" ? true : false);
        }

        private void Share(DataTransferManager sender, DataRequestedEventArgs args)
        {
            Methods.Share(args,
                item.Snippet.Thumbnails.Medium.Url,
                item.Snippet.Title,
                $"https://www.youtube.com/watch?v={item.Id}",
                resources.GetString("/Cards/videoShare"));
        }

        private void share_Click(object sender, RoutedEventArgs e)
        {
            DataTransferManager.GetForCurrentView().DataRequested += new TypedEventHandler<DataTransferManager, DataRequestedEventArgs>(Share);
            DataTransferManager.ShowShareUI();
        }

        private void ViewChannel_Click(object sender, RoutedEventArgs e)
        {
            Methods.MainPage.GoToChannel(item.Snippet.ChannelId);
        }

        private void GetLink_Click(object sender, RoutedEventArgs e)
        {
            DataPackage data = new DataPackage();
            data.SetText($"https://www.youtube.com/watch?v={item.Id}");
            Clipboard.SetContent(data);
        }

        private async void InBrowser_Click(object sender, RoutedEventArgs e)
        {
            await Launcher.LaunchUriAsync($"https://www.youtube.com/watch?v={item.Id}".ToUri());
        }

        private void Thumbnail_ImageOpened(object sender, RoutedEventArgs e)
        {
            showThumb.Begin();
        }

        private async void NewPlaylist_Click(object sender, RoutedEventArgs e)
        {
            StackPanel stack = new StackPanel();
            stack.Children.Add(new TextBox
            {
                PlaceholderText = resources.GetString("/VideoPage/newPlaylistName/PlaceholderText")
            });

            ComboBox comboBox = new ComboBox
            {
                Header = resources.GetString("/VideoPage/privacy/Header"),
                SelectedIndex = 0,
                HorizontalAlignment = HorizontalAlignment.Stretch
            };
            comboBox.Items.Add(new ComboBoxItem { Content = resources.GetString("/VideoPage/public/Content") });
            comboBox.Items.Add(new ComboBoxItem { Content = resources.GetString("/VideoPage/private/Content") });
            comboBox.Items.Add(new ComboBoxItem { Content = resources.GetString("/VideoPage/direct/Content") });

            stack.Children.Add(comboBox);

            ContentDialog playlistDialog = new ContentDialog
            {
                PrimaryButtonText = resources.GetString("/VideoPage/dialog/PrimaryButtonText"),
                CloseButtonText = resources.GetString("/VideoPage/dialog/CloseButtonText"),
                DefaultButton = ContentDialogButton.Primary,
                Title = resources.GetString("/VideoPage/dialog/Title"),
                Content = stack
            };
            playlistDialog.PrimaryButtonClick += PlaylistDialog_PrimaryButtonClick;
            await playlistDialog.ShowAsync();
        }

        private async void PlaylistDialog_PrimaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args)
        {
            string privacy = "private";
            switch (((sender.Content as StackPanel).Children[1] as ComboBox).SelectedIndex)
            {
                case 0:
                    privacy = "public";
                    break;
                case 1:
                    privacy = "private";
                    break;
                case 2:
                    privacy = "unlisted";
                    break;
            }

            Playlist newItem = new Playlist
            {
                Snippet = new PlaylistSnippet
                {
                    Title = ((sender.Content as StackPanel).Children[0] as TextBox).Text
                },
                Status = new PlaylistStatus
                {
                    PrivacyStatus = privacy,
                }
            };

            Playlist i;

            try { i = await SecretsVault.Service.Playlists.Insert(newItem, "snippet,status").ExecuteAsync(); }
            catch
            {
                return;
            }

            ToggleMenuFlyoutItem menuItem = new ToggleMenuFlyoutItem
            {
                Text = i.Snippet.Title,
                IsChecked = true,
                Tag = i,
                Icon = new FontIcon
                {
                    Glyph = "\xE728"
                }
            };
            menuItem.Click += Item_Click;
            addTo.Items.Add(menuItem);

            Item_Click(menuItem, null);
        }

        private async void Wl_Click(object sender, RoutedEventArgs e)
        {
            if (wl.IsChecked)
            {
                try
                {
                    PlaylistItem playlist = new PlaylistItem
                    {
                        Snippet = new PlaylistItemSnippet
                        {
                            PlaylistId = "WL",
                            ResourceId = new ResourceId
                            {
                                VideoId = item.Id,
                                Kind = "youtube#video"
                            }
                        }
                    };
                    PlaylistItemsResource.InsertRequest request = SecretsVault.Service.PlaylistItems.Insert(playlist, "snippet");

                    await request.ExecuteAsync();
                }
                catch
                {
                    wl.IsChecked = false;
                }
            }
            else
                wl.IsChecked = true;
        }

        async void LoadAddTo()
        {
            try
            {
                if (SecretsVault.UserChannel == null)
                {
                    addTo.Visibility = Visibility.Collapsed;
                    return;
                }

                if (SecretsVault.WatchLater.Contains(item.Id))
                    (addTo.Items[1] as ToggleMenuFlyoutItem).IsChecked = true;

                PlaylistsResource.ListRequest request = SecretsVault.Service.Playlists.List("snippet");
                request.Mine = true;
                request.MaxResults = 50;

                PlaylistListResponse response = await request.ExecuteAsync();

                PlaylistItemsResource.ListRequest itemRequest = SecretsVault.Service.PlaylistItems.List("snippet");
                itemRequest.VideoId = item.Id;

                foreach (Playlist i in response.Items)
                {
                    itemRequest.PlaylistId = i.Id;
                    ToggleMenuFlyoutItem menuItem = new ToggleMenuFlyoutItem
                    {
                        Text = i.Snippet.Title,
                        IsChecked = (await itemRequest.ExecuteAsync()).Items.Count > 0,
                        Tag = i,
                        Icon = new FontIcon
                        {
                            Glyph = "\xE728"
                        }
                    };
                    menuItem.Click += Item_Click;
                    addTo.Items.Add(menuItem);
                }
            }
            catch
            {
                addTo.Visibility = Visibility.Collapsed;
            }
        }

        private async void Item_Click(object sender, RoutedEventArgs e)
        {
            if (((ToggleMenuFlyoutItem)sender).IsChecked)
            {
                try
                {
                    PlaylistItem playlist = new PlaylistItem
                    {
                        Snippet = new PlaylistItemSnippet
                        {
                            PlaylistId = (((ToggleMenuFlyoutItem)sender).Tag as Playlist).Id,
                            ResourceId = new ResourceId
                            {
                                VideoId = item.Id,
                                Kind = "youtube#video"
                            }
                        }
                    };
                    PlaylistItemsResource.InsertRequest request = SecretsVault.Service.PlaylistItems.Insert(playlist, "snippet");

                    await request.ExecuteAsync();
                }
                catch
                {
                    ((ToggleMenuFlyoutItem)sender).IsChecked = false;
                }
            }
            else
            {
                try
                {
                    PlaylistItemsResource.ListRequest itemRequest = SecretsVault.Service.PlaylistItems.List("snippet");
                    itemRequest.VideoId = item.Id;
                    itemRequest.PlaylistId = ((Playlist)((ToggleMenuFlyoutItem)sender).Tag).Id;

                    PlaylistItemsResource.DeleteRequest request = SecretsVault.Service.PlaylistItems.Delete((await itemRequest.ExecuteAsync()).Items[0].Id);

                    await request.ExecuteAsync();
                }
                catch
                {
                    ((ToggleMenuFlyoutItem)sender).IsChecked = true;
                }
            }
        }

        private async void Delete_Click(object sender, RoutedEventArgs e)
        {
            if (playlistId == "WL")
            {
                await Launcher.LaunchUriAsync("https://youtube.com/playlist?list=WL".ToUri());
                return;
            }
            else if(playlistId == "HL")
            {
                if (history == null)
                    await Launcher.LaunchUriAsync("https://youtube.com/feed/history".ToUri());
                else
                {
                    HistorySet.Delete(history);
                    (Methods.MainPage.PageContent.Frame.Content as History).Delete(this);
                }
                return;
            }
            try
            {
                PlaylistItemsResource.ListRequest request = SecretsVault.Service.PlaylistItems.List("snippet");
                request.PlaylistId = playlistId;
                request.VideoId = item.Id;
                PlaylistItemListResponse response = await request.ExecuteAsync();

                PlaylistItem playlistItem = response.Items.Find(i => i.Snippet.PlaylistId == playlistId);

                await SecretsVault.Service.PlaylistItems.Delete(playlistItem.Id).ExecuteAsync();

                (Methods.MainPage.PageContent.Frame.Content as PlaylistPage).DeleteItem(this);
            }
            catch
            {

            }
        }

        private void Card_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            Height = e.NewSize.Width * 0.75;
        }
    }
}
