using System;
using System.Collections.Generic;
using System.Linq;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;
using Google.Apis.YouTube.v3;
using Google.Apis.YouTube.v3.Data;
using Windows.UI.Xaml.Media.Imaging;
using Windows.UI.Popups;
using Windows.ApplicationModel.Resources;
using Microsoft.AppCenter.Analytics;

namespace FoxTube.Controls
{
    public enum CommentType { TopLevel, Reply }
    /// <summary>
    /// Control represents video comment entity
    /// </summary>
    public sealed partial class CommentCard : UserControl
    {
        ResourceLoader resources = ResourceLoader.GetForCurrentView("CommentsPage");

        public Comment item;
        public CommentThread thread;
        CommentType type;

        bool repliesLoaded = false;

        public CommentCard(CommentThread comment)
        {
            InitializeComponent();
            Initialize(comment);
        }

        public void Initialize(CommentThread comment)
        {
            item = comment.Snippet.TopLevelComment;
            thread = comment;

            replyBtn.Visibility = comment.Snippet.CanReply.Value && SecretsVault.IsAuthorized ? Visibility.Visible : Visibility.Collapsed;
            spam.Visibility = SecretsVault.IsAuthorized ? Visibility.Visible : Visibility.Collapsed;
            if (!comment.Snippet.TotalReplyCount.HasValue || comment.Snippet.TotalReplyCount.Value == 0)
                showReplies.Visibility = Visibility.Collapsed;
            else
                ((showReplies.Content as StackPanel).Children[1] as TextBlock).Text = comment.Snippet.TotalReplyCount.ToString();

            if (comment.Snippet.TopLevelComment.Snippet.CanRate == false)
            {
                upvote.Visibility = Visibility.Collapsed;
                rating.Visibility = Visibility.Collapsed;
            }
            else
                rating.Text = comment.Snippet.TopLevelComment.Snippet.LikeCount.HasValue ? comment.Snippet.TopLevelComment.Snippet.LikeCount.ToString() : "";

            if(item.Snippet.AuthorChannelId != null)
            {
                if (item.Snippet.AuthorChannelId.ToString().Split('"')[3] == SecretsVault.AccountId)
                {
                    (specialAuthor.Child as TextBlock).Text = comment.Snippet.TopLevelComment.Snippet.AuthorDisplayName;
                    specialAuthor.Visibility = Visibility.Visible;
                    author.Visibility = Visibility.Collapsed;
                    editBtn.Visibility = Visibility.Visible;
                }
                else if (item.Snippet.AuthorChannelId.ToString().Split('"')[3] == item.Snippet.ChannelId)
                {
                    (specialAuthor.Child as TextBlock).Text = comment.Snippet.TopLevelComment.Snippet.AuthorDisplayName;
                    specialAuthor.Visibility = Visibility.Visible;
                    author.Visibility = Visibility.Collapsed;
                }
            }
            author.Text = comment.Snippet.TopLevelComment.Snippet.AuthorDisplayName;

            meta.Text = string.Format("{0} {1}", Methods.GetAgo(comment.Snippet.TopLevelComment.Snippet.PublishedAt.Value), comment.Snippet.TopLevelComment.Snippet.UpdatedAt != comment.Snippet.TopLevelComment.Snippet.PublishedAt ? resources.GetString("/CommentsPage/edited") : "");
            text.FormatText(comment.Snippet.TopLevelComment.Snippet.TextDisplay);

            try { avatar.ProfilePicture = new BitmapImage(new Uri(comment.Snippet.TopLevelComment.Snippet.AuthorProfileImageUrl)) { DecodePixelWidth = 50, DecodePixelHeight = 50 }; }
            catch { }
        }

        public void DeleteComment(CommentCard comment)
        {
            replies.Children.Remove(comment);

            ((showReplies.Content as StackPanel).Children[1] as TextBlock).Text = (--thread.Snippet.TotalReplyCount).ToString();

            if(thread.Snippet.TotalReplyCount == 0)
                showReplies.Visibility = Visibility.Collapsed;

        }
        
        public CommentCard(Comment comment)
        {
            InitializeComponent();
            Initialize(comment);
        }

        public void Initialize(Comment comment)
        {
            item = comment;
            type = CommentType.Reply;

            replyBtn.Visibility = Visibility.Collapsed;
            showReplies.Visibility = Visibility.Collapsed;
            spam.Visibility = SecretsVault.IsAuthorized ? Visibility.Visible : Visibility.Collapsed;

            if (comment.Snippet.CanRate == false)
            {
                upvote.Visibility = Visibility.Collapsed;
                rating.Visibility = Visibility.Collapsed;
            }
            else
                rating.Text = comment.Snippet.LikeCount.HasValue ? comment.Snippet.LikeCount.ToString() : "";

            if (item.Snippet.AuthorChannelId.ToString().Split('"')[3] == SecretsVault.AccountId)
            {
                (specialAuthor.Child as TextBlock).Text = comment.Snippet.AuthorDisplayName;
                specialAuthor.Visibility = Visibility.Visible;
                author.Visibility = Visibility.Collapsed;
                editBtn.Visibility = Visibility.Visible;
            }
            else if (item.Snippet.AuthorChannelId.ToString().Split('"')[3] == item.Snippet.ChannelId)
            {
                (specialAuthor.Child as TextBlock).Text = comment.Snippet.AuthorDisplayName;
                specialAuthor.Visibility = Visibility.Visible;
                author.Visibility = Visibility.Collapsed;
            }
            else
                author.Text = comment.Snippet.AuthorDisplayName;

            meta.Text = string.Format("{0} {1}", Methods.GetAgo(comment.Snippet.PublishedAt.Value), comment.Snippet.UpdatedAt != comment.Snippet.PublishedAt ? resources.GetString("/CommentsPage/edited") : "");
            text.FormatText(comment.Snippet.TextDisplay);

            try { avatar.ProfilePicture = new BitmapImage(new Uri(comment.Snippet.AuthorProfileImageUrl)) { DecodePixelWidth = 50, DecodePixelHeight = 50 }; }
            catch { }
        }

        private void replyBtn_Click(object sender, RoutedEventArgs e)
        {
            replyEditor.Visibility = replyEditor.Visibility == Visibility.Visible ? Visibility.Collapsed : Visibility.Visible;
        }

        private async void showReplies_Click(object sender, RoutedEventArgs e)
        {
            replies.Visibility = replies.Visibility == Visibility.Visible ? Visibility.Collapsed : Visibility.Visible;

            if (repliesLoaded)
                return;

            processing.Visibility = Visibility.Visible;

            CommentsResource.ListRequest request = SecretsVault.Service.Comments.List("snippet");
            request.ParentId = item.Id;
            request.TextFormat = CommentsResource.ListRequest.TextFormatEnum.PlainText;
            request.MaxResults = 50;
            
            CommentListResponse response;

            do
            {
                response = await request.ExecuteAsync();
                request.PageToken = response.NextPageToken;

                response.Items.ForEach(i => replies.Children.Add(new CommentCard(i)));
            }
            while (!string.IsNullOrWhiteSpace(request.PageToken));

            repliesLoaded = true;
            processing.Visibility = Visibility.Collapsed;
        }

        private void avatar_Tapped(object sender, TappedRoutedEventArgs e)
        {
            Methods.MainPage.GoToChannel(item.Snippet.AuthorChannelId.ToString().Split('"')[3]);
        }

        private void reply_TextChanged(object sender, TextChangedEventArgs e)
        {
            send.IsEnabled = reply.Text.Length == 0 ? false : true;
        }

        private async void send_Click(object sender, RoutedEventArgs args)
        {
            if (string.IsNullOrWhiteSpace(reply.Text))
                return;

            send.IsEnabled = false;
            reply.IsEnabled = false;
            processing.Visibility = Visibility.Visible;

            Comment comment = new Comment()
            {
                Snippet = new CommentSnippet()
                {
                    TextOriginal = reply.Text,
                    ParentId = item.Id
                }
            };

            try
            {
                Comment response = await SecretsVault.Service.Comments.Insert(comment, "snippet").ExecuteAsync();
                reply.Text = "";
                replyEditor.Visibility = Visibility.Collapsed;
                if (repliesLoaded)
                    replies.Children.Insert(0, new CommentCard(response));
                else
                    showReplies_Click(this, null);

                showReplies.Visibility = Visibility.Visible;
                ((showReplies.Content as StackPanel).Children[1] as TextBlock).Text = (++thread.Snippet.TotalReplyCount).ToString();
            }
            catch (Exception e)
            {
                await new MessageDialog(resources.GetString("/CommentsPage/failedReply")).ShowAsync();
                Analytics.TrackEvent("Failed to send comment reply", new Dictionary<string, string>()
                {
                    { "Exception", e.GetType().ToString() },
                    { "Message", e.Message },
                    { "Top comment ID", item.Id },
                    { "StackTrace", e.StackTrace }
                });
            }

            send.IsEnabled = true;
            reply.IsEnabled = true;
            processing.Visibility = Visibility.Collapsed;
        }

        private void editorClose_Click(object sender, RoutedEventArgs e)
        {
            editor.Visibility = Visibility.Collapsed;
            text.Visibility = Visibility.Visible;
            toolbar.Visibility = Visibility.Visible;
        }

        private async void editorSend_Click(object sender, RoutedEventArgs args)
        {
            if (string.IsNullOrWhiteSpace(editorText.Text))
                return;

            editorText.IsEnabled = false;
            editorSend.IsEnabled = false;
            editorClose.IsEnabled = false;
            deleteComment.IsEnabled = false;
            processing.Visibility = Visibility.Visible;

            try
            {
                item.Snippet.TextOriginal = editorText.Text;
                item.Snippet.UpdatedAt = DateTime.Now;

                if (type == CommentType.Reply)
                    await SecretsVault.Service.Comments.Update(item, "snippet").ExecuteAsync();
                else
                {
                    thread.Snippet.TopLevelComment = item;
                    await SecretsVault.Service.CommentThreads.Update(thread, "snippet").ExecuteAsync();
                }

                text.Text = editorText.Text;
                meta.Text = $"{Methods.GetAgo(item.Snippet.PublishedAt.Value)} {resources.GetString("/CommentsPage/edited")}";

                editor.Visibility = Visibility.Collapsed;
                text.Visibility = Visibility.Visible;
                toolbar.Visibility = Visibility.Visible;
            }
            catch (Exception e)
            {
                await new MessageDialog(resources.GetString("/CommentsPage/failedEdit")).ShowAsync();
                Analytics.TrackEvent("Failed to edit comment", new Dictionary<string, string>()
                {
                    { "Exception", e.GetType().ToString() },
                    { "Message", e.Message },
                    { "StackTrace", e.StackTrace }
                });
            }

            editorText.IsEnabled = true;
            editorSend.IsEnabled = true;
            editorClose.IsEnabled = true;
            deleteComment.IsEnabled = true;
            processing.Visibility = Visibility.Collapsed;
        }

        private void editorText_TextChanged(object sender, TextChangedEventArgs e)
        {
            editorSend.IsEnabled = editorText.Text.Length == 0 ? false : true;
        }

        private void editBtn_Click(object sender, RoutedEventArgs e)
        {
            editor.Visibility = Visibility.Visible;
            toolbar.Visibility = Visibility.Collapsed;

            text.Visibility = Visibility.Collapsed;
            editorText.Text = text.Text;
        }

        private async void DeleteComment_Click(object sender, RoutedEventArgs args)
        {
            MessageDialog dialog = new MessageDialog(resources.GetString("/CommentsPage/deleteContent"), resources.GetString("/CommentsPage/deleteHeader"));

            dialog.Commands.Add(new UICommand(resources.GetString("/CommentsPage/yes"), async (command) =>
            {
                try
                {
                    await SecretsVault.Service.Comments.Delete(item.Id).ExecuteAsync();
                    if (type == CommentType.Reply)
                        Methods.CommentsPage.RemoveComment(this, item.Snippet.ParentId);
                    else
                        Methods.CommentsPage.RemoveComment(this);
                }
                catch (Exception e)
                {
                    await new MessageDialog(resources.GetString("/CommentsPage/failedDelete")).ShowAsync();
                    Analytics.TrackEvent("Failed delete comment", new Dictionary<string, string>()
                    {
                        { "Exception", e.GetType().ToString() },
                        { "Message", e.Message },
                        { "StackTrace", e.StackTrace }
                    });
                }
            }));
            dialog.Commands.Add(new UICommand(resources.GetString("/CommentsPage/no")));

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

            await dialog.ShowAsync();
        }

        private async void MarkAsSpam_Click(object sender, RoutedEventArgs e)
        {
            ResourceLoader resources = ResourceLoader.GetForCurrentView("Report");
            try { await SecretsVault.Service.Comments.MarkAsSpam(item.Id).ExecuteAsync(); }
            catch
            {
                await new MessageDialog(resources.GetString("/Report/err")).ShowAsync();
                return;
            }
            await new MessageDialog(resources.GetString("/Report/submittedHeader"), resources.GetString("/Report/submittedBody")).ShowAsync();
        }
    }
}
