using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Input;
using Pixiview.Resources;
using Pixiview.UI;
using Pixiview.UI.Theme;
using Pixiview.Utils;
using Xamarin.Essentials;
using Xamarin.Forms;

namespace Pixiview.Illust
{
    [QueryProperty("IllustId", "id")]
    public partial class ViewIllustPage : AdaptedPage
    {
        public static readonly BindableProperty FavoriteIconProperty = BindableProperty.Create(
            nameof(FavoriteIcon), typeof(ImageSource), typeof(ViewIllustPage));
        public static readonly BindableProperty IllustsProperty = BindableProperty.Create(
            nameof(Illusts), typeof(IllustDetailItem[]), typeof(ViewIllustPage));
        public static readonly BindableProperty PagePositionTextProperty = BindableProperty.Create(
            nameof(PagePositionText), typeof(string), typeof(ViewIllustPage));
        public static readonly BindableProperty IsPageVisibleProperty = BindableProperty.Create(
            nameof(IsPageVisible), typeof(bool), typeof(ViewIllustPage));
        public static readonly BindableProperty IllustItemProperty = BindableProperty.Create(
            nameof(IllustItem), typeof(IllustItem), typeof(ViewIllustPage));

        public ImageSource FavoriteIcon
        {
            get => (ImageSource)GetValue(FavoriteIconProperty);
            set => SetValue(FavoriteIconProperty, value);
        }

        public IllustDetailItem[] Illusts
        {
            get => (IllustDetailItem[])GetValue(IllustsProperty);
            set => SetValue(IllustsProperty, value);
        }
        public string PagePositionText
        {
            get => (string)GetValue(PagePositionTextProperty);
            set => SetValue(PagePositionTextProperty, value);
        }
        public bool IsPageVisible
        {
            get => (bool)GetValue(IsPageVisibleProperty);
            set => SetValue(IsPageVisibleProperty, value);
        }
        public IllustItem IllustItem
        {
            get => (IllustItem)GetValue(IllustItemProperty);
            set => SetValue(IllustItemProperty, value);
        }

        public int CurrentPage { get; private set; }

        private readonly IIllustCollectionPage collectionPage;
        private readonly ICommand longPressed;
        private readonly ImageSource fontIconLove;
        private readonly ImageSource fontIconNotLove;

        public ViewIllustPage(IllustItem illust, IIllustCollectionPage page)
        {
            IllustItem = illust;
            collectionPage = page;
            longPressed = new Command<IllustDetailItem>(Illust_LongPressed);
            BindingContext = this;

            fontIconLove = (ImageSource)Application.Current.Resources[ThemeBase.FontIconLove];
            fontIconNotLove = (ImageSource)Application.Current.Resources[ThemeBase.FontIconNotLove];
            var favorites = Stores.Favorites;
            FavoriteIcon = favorites.Any(i => i.Id == illust.Id)
                ? fontIconLove
                : fontIconNotLove;

            InitializeComponent();

            if (illust != null)
            {
                LoadIllust(illust);
            }
        }

        public override void OnLoad()
        {
            OnOrientationChanged(CurrentOrientation);
        }

        protected override void OnAppearing()
        {
            base.OnAppearing();
            Screen.SetHomeIndicatorAutoHidden(Shell.Current, true);
        }

        protected override void OnDisappearing()
        {
            base.OnDisappearing();

            if (collectionPage is IllustDataCollectionPage)
            {
                Stores.SaveFavoritesIllusts();
            }
            Screen.SetHomeIndicatorAutoHidden(Shell.Current, false);
        }

        private void LoadIllust(IllustItem illust)
        {
            if (illust == null)
            {
                return;
            }

            var items = new IllustDetailItem[illust.PageCount];
            if (items.Length > 1)
            {
                IsPageVisible = true;
                PagePositionText = $"1/{items.Length}";
            }
            else
            {
                IsPageVisible = false;
            }

            for (var i = 0; i < items.Length; i++)
            {
                items[i] = new IllustDetailItem
                {
                    LongPressed = longPressed
                };
                if (i == 0)
                {
                    items[i].Loading = true;
                    items[i].Image = illust.Image;
                }
            }

            Illusts = items;
            Task.Run(DoLoadImages);
        }

        private void DoLoadImages()
        {
            var illustItem = IllustItem;
            var pages = Stores.LoadIllustPageData(illustItem.Id);
            if (pages == null)
            {
                App.DebugError("illustPage.load", $"failed to load illust page data, id: {illustItem.Id}");
                return;
            }
            var items = Illusts;
            if (pages.body.Length > items.Length)
            {
                App.DebugPrint($"local page count ({items.Length}) is not equals the remote one ({pages.body.Length})");
                var tmp = new IllustDetailItem[pages.body.Length];
                items.CopyTo(items, 0);
                for (var i = items.Length; i < tmp.Length; i++)
                {
                    tmp[i] = new IllustDetailItem
                    {
                        LongPressed = longPressed
                    };
                }
                items = tmp;
            }

            for (var i = 0; i < items.Length; i++)
            {
                var item = items[i];
                var p = pages.body[i];
                item.PreviewUrl = p.urls.regular;
                item.OriginalUrl = p.urls.original;
            }

            DoLoadImage(0, true);
            var image = items[0].Image;
            if (image != null)
            {
                illustItem.Image = image;
            }
            if (items.Length > 1)
            {
                DoLoadImage(1);
            }
        }

        private void DoLoadImage(int index, bool force = false)
        {
            var items = Illusts;
            if (index < 0 || index >= items.Length)
            {
                App.DebugPrint($"invalid index: {index}");
                return;
            }

            var item = items[index];
            if (!force)
            {
                if (item.Loading || (index > 0 && item.Image != null))
                {
                    App.DebugPrint($"skipped, loading or already loaded, index: {index}, loading: {item.Loading}");
                    return;
                }
            }
            item.Loading = true;
            var image = Stores.LoadPreviewImage(item.PreviewUrl);
            if (image != null)
            {
                item.Image = image;
            }
            item.Loading = false;
        }

        private void CarouselView_PositionChanged(object sender, PositionChangedEventArgs e)
        {
            var index = e.CurrentPosition;
            CurrentPage = index;
            var items = Illusts;
            var length = items.Length;
            PagePositionText = $"{index + 1}/{length}";

            var item = items[index];
            if (!item.Loading && item.Image == null)
            {
                Task.Run(() => DoLoadImage(index));
            }
            if (index < length - 1)
            {
                item = items[index + 1];
                if (!item.Loading && item.Image == null)
                {
                    Task.Run(() => DoLoadImage(index + 1));
                }
            }
        }

        private void Favorite_Clicked(object sender, EventArgs e)
        {
            var favorites = Stores.Favorites;
            var illust = IllustItem;
            var index = favorites.FindIndex(i => i.Id == illust.Id);
            if (index < 0)
            {
                illust.IsFavorite = true;
                favorites.Insert(0, illust);
                FavoriteIcon = fontIconLove;
            }
            else
            {
                illust.IsFavorite = false;
                favorites.RemoveAt(index);
                FavoriteIcon = fontIconNotLove;
            }
        }

        private async void Illust_LongPressed(IllustDetailItem item)
        {
            List<string> extras = new List<string>();
            var share = ResourceHelper.Share;
            var preview = Stores.GetPreviewImagePath(item.PreviewUrl);
            if (preview != null)
            {
                extras.Add(share);
            }
            var saveOriginal = ResourceHelper.SaveOriginal;
            var userDetail = ResourceHelper.UserDetail;
            extras.Add(userDetail);

            var illustItem = IllustItem;
            var result = await DisplayActionSheet(
                illustItem.Title,
                ResourceHelper.Cancel,
                saveOriginal,
                extras.ToArray());
            if (result == saveOriginal)
            {
                SaveOriginalImage(item);
            }
            else if (result == share)
            {
                await Share.RequestAsync(new ShareFileRequest
                {
                    Title = illustItem.Title,
                    File = new ShareFile(preview)
                });
            }
            else if (result == userDetail)
            {
                var page = new UserIllustPage(illustItem);
                await Navigation.PushAsync(page);
            }
        }

        private async void SaveOriginalImage(IllustDetailItem item)
        {
            if (Stores.CheckIllustImage(item.OriginalUrl))
            {
                var flag = await DisplayAlert(ResourceHelper.Operation,
                    ResourceHelper.AlreadySavedQuestion,
                    ResourceHelper.Yes,
                    ResourceHelper.No);
                if (!flag)
                {
                    return;
                }
            }

            var status = await Permissions.CheckStatusAsync<Permissions.Photos>();
            if (status != PermissionStatus.Granted)
            {
                status = await Permissions.RequestAsync<Permissions.Photos>();
                if (status != PermissionStatus.Granted)
                {
                    App.DebugPrint("access denied to gallery.");
                    return;
                }
            }

            if (item == null || item.Downloading)
            {
                return;
            }
            item.Downloading = true;
            _ = Task.Run(() => DoLoadOriginalImage(item));
        }

        private void DoLoadOriginalImage(IllustDetailItem item)
        {
            var image = Stores.LoadIllustImage(item.OriginalUrl);
            if (image != null)
            {
                Device.BeginInvokeOnMainThread(async () =>
                {
                    var service = DependencyService.Get<IFileStore>();
                    var result = await service.SaveImageToGalleryAsync(image);

                    string message = result ?? ResourceHelper.SaveSuccess;
                    await DisplayAlert(ResourceHelper.Title, message, ResourceHelper.Ok);
                });
            }
            item.Downloading = false;
        }
    }

    public class IllustDetailItem : BindableObject
    {
        public static readonly BindableProperty ImageProperty = BindableProperty.Create(
            nameof(Image), typeof(ImageSource), typeof(IllustDetailItem));
        public static readonly BindableProperty LoadingProperty = BindableProperty.Create(
            nameof(Loading), typeof(bool), typeof(IllustDetailItem));
        public static readonly BindableProperty DownloadingProperty = BindableProperty.Create(
            nameof(Downloading), typeof(bool), typeof(IllustDetailItem));

        public ImageSource Image
        {
            get => (ImageSource)GetValue(ImageProperty);
            set => SetValue(ImageProperty, value);
        }
        public bool Loading
        {
            get => (bool)GetValue(LoadingProperty);
            set => SetValue(LoadingProperty, value);
        }
        public bool Downloading
        {
            get => (bool)GetValue(DownloadingProperty);
            set => SetValue(DownloadingProperty, value);
        }
        public ICommand LongPressed { get; set; }
        public string PreviewUrl { get; set; }
        public string OriginalUrl { get; set; }
    }
}
