// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE

using System.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Beatmaps;
using osu.Game.Graphics;
using OpenTK;
using OpenTK.Graphics;

namespace osu.Game.Overlays.Music
{
    public class PlaylistOverlay : OverlayContainer
    {
        private const float transition_duration = 600;

        private const float playlist_height = 510;

        private FilterControl filter;
        private PlaylistList list;

        private BeatmapManager beatmaps;

        private readonly Bindable<WorkingBeatmap> beatmapBacking = new Bindable<WorkingBeatmap>();

        public IEnumerable<BeatmapSetInfo> BeatmapSets;

        [BackgroundDependencyLoader]
        private void load(OsuGameBase game, BeatmapManager beatmaps, OsuColour colours)
        {
            this.beatmaps = beatmaps;

            Children = new Drawable[]
            {
                new Container
                {
                    RelativeSizeAxes = Axes.Both,
                    CornerRadius = 5,
                    Masking = true,
                    EdgeEffect = new EdgeEffectParameters
                    {
                        Type = EdgeEffectType.Shadow,
                        Colour = Color4.Black.Opacity(40),
                        Radius = 5,
                    },
                    Children = new Drawable[]
                    {
                        new Box
                        {
                            Colour = colours.Gray3,
                            RelativeSizeAxes = Axes.Both,
                        },
                        list = new PlaylistList
                        {
                            RelativeSizeAxes = Axes.Both,
                            Padding = new MarginPadding { Top = 95, Bottom = 10, Right = 10 },
                            OnSelect = itemSelected,
                        },
                        filter = new FilterControl
                        {
                            RelativeSizeAxes = Axes.X,
                            AutoSizeAxes = Axes.Y,
                            ExitRequested = () => State = Visibility.Hidden,
                            FilterChanged = search => list.Filter(search),
                            Padding = new MarginPadding(10),
                        },
                    },
                },
            };

            beatmaps.BeatmapSetAdded += s => Schedule(() => list.AddBeatmapSet(s));
            beatmaps.BeatmapSetRemoved += s => Schedule(() => list.RemoveBeatmapSet(s));

            list.BeatmapSets = BeatmapSets = beatmaps.GetAllUsableBeatmapSets();


            beatmapBacking.BindTo(game.Beatmap);

            filter.Search.OnCommit = (sender, newText) =>
            {
                var beatmap = list.FirstVisibleSet?.Beatmaps?.FirstOrDefault();
                if (beatmap != null) playSpecified(beatmap);
            };
        }

        protected override void LoadComplete()
        {
            base.LoadComplete();
            beatmapBacking.ValueChanged += b => list.SelectedSet = b?.BeatmapSetInfo;
            beatmapBacking.TriggerChange();
        }

        protected override void PopIn()
        {
            filter.Search.HoldFocus = true;
            Schedule(() => GetContainingInputManager().ChangeFocus(filter.Search));

            this.ResizeTo(new Vector2(1, playlist_height), transition_duration, Easing.OutQuint);
            this.FadeIn(transition_duration, Easing.OutQuint);
        }

        protected override void PopOut()
        {
            filter.Search.HoldFocus = false;

            this.ResizeTo(new Vector2(1, 0), transition_duration, Easing.OutQuint);
            this.FadeOut(transition_duration);
        }

        private void itemSelected(BeatmapSetInfo set)
        {
            if (set.ID == (beatmapBacking.Value?.BeatmapSetInfo?.ID ?? -1))
            {
                beatmapBacking.Value?.Track?.Seek(0);
                return;
            }

            playSpecified(set.Beatmaps[0]);
        }

        public void PlayPrevious()
        {
            var playable = list.PreviousSet;

            if (playable != null)
            {
                playSpecified(playable.Beatmaps[0]);
                list.SelectedSet = playable;
            }
        }

        public void PlayNext()
        {
            var playable = list.NextSet;

            if (playable != null)
            {
                playSpecified(playable.Beatmaps[0]);
                list.SelectedSet = playable;
            }
        }

        private void playSpecified(BeatmapInfo info)
        {
            beatmapBacking.Value = beatmaps.GetWorkingBeatmap(info, beatmapBacking);
            beatmapBacking.Value.Track.Start();
        }
    }

    //todo: placeholder
    public enum PlaylistCollection
    {
        All
    }
}