// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

using System;
using System.Threading;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API;
using osu.Game.Overlays.Dashboard;
using osu.Game.Overlays.Dashboard.Friends;

namespace osu.Game.Overlays
{
    public class DashboardOverlay : FullscreenOverlay
    {
        private CancellationTokenSource cancellationToken;

        private Box background;
        private Container content;
        private DashboardOverlayHeader header;
        private LoadingLayer loading;
        private OverlayScrollContainer scrollFlow;

        public DashboardOverlay()
            : base(OverlayColourScheme.Purple)
        {
        }

        [BackgroundDependencyLoader]
        private void load()
        {
            Children = new Drawable[]
            {
                background = new Box
                {
                    RelativeSizeAxes = Axes.Both
                },
                scrollFlow = new OverlayScrollContainer
                {
                    RelativeSizeAxes = Axes.Both,
                    ScrollbarVisible = false,
                    Child = new FillFlowContainer
                    {
                        AutoSizeAxes = Axes.Y,
                        RelativeSizeAxes = Axes.X,
                        Direction = FillDirection.Vertical,
                        Children = new Drawable[]
                        {
                            header = new DashboardOverlayHeader
                            {
                                Anchor = Anchor.TopCentre,
                                Origin = Anchor.TopCentre,
                                Depth = -float.MaxValue
                            },
                            content = new Container
                            {
                                RelativeSizeAxes = Axes.X,
                                AutoSizeAxes = Axes.Y
                            }
                        }
                    }
                },
                loading = new LoadingLayer(content),
            };

            background.Colour = ColourProvider.Background5;
        }

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

            header.Current.BindValueChanged(onTabChanged);
        }

        private bool displayUpdateRequired = true;

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

            // We don't want to create a new display on every call, only when exiting from fully closed state.
            if (displayUpdateRequired)
            {
                header.Current.TriggerChange();
                displayUpdateRequired = false;
            }
        }

        protected override void PopOutComplete()
        {
            base.PopOutComplete();
            loadDisplay(Empty());
            displayUpdateRequired = true;
        }

        private void loadDisplay(Drawable display)
        {
            scrollFlow.ScrollToStart();

            LoadComponentAsync(display, loaded =>
            {
                if (API.IsLoggedIn)
                    loading.Hide();

                content.Child = loaded;
            }, (cancellationToken = new CancellationTokenSource()).Token);
        }

        private void onTabChanged(ValueChangedEvent<DashboardOverlayTabs> tab)
        {
            cancellationToken?.Cancel();
            loading.Show();

            if (!API.IsLoggedIn)
            {
                loadDisplay(Empty());
                return;
            }

            switch (tab.NewValue)
            {
                case DashboardOverlayTabs.Friends:
                    loadDisplay(new FriendDisplay());
                    break;

                default:
                    throw new NotImplementedException($"Display for {tab.NewValue} tab is not implemented");
            }
        }

        public override void APIStateChanged(IAPIProvider api, APIState state)
        {
            if (State.Value == Visibility.Hidden)
                return;

            header.Current.TriggerChange();
        }

        protected override void Dispose(bool isDisposing)
        {
            cancellationToken?.Cancel();
            base.Dispose(isDisposing);
        }
    }
}