// 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.Linq;
using osu.Framework.Allocation;
using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Chat;
using osu.Game.Online.Leaderboards;
using osu.Game.Rulesets;

namespace osu.Game.Overlays.Profile.Sections.Recent
{
    public partial class DrawableRecentActivity : CompositeDrawable
    {
        private const int font_size = 14;

        [Resolved]
        private IAPIProvider api { get; set; } = null!;

        [Resolved]
        private IRulesetStore rulesets { get; set; } = null!;

        private readonly APIRecentActivity activity;

        private LinkFlowContainer content = null!;

        public DrawableRecentActivity(APIRecentActivity activity)
        {
            this.activity = activity;
        }

        [BackgroundDependencyLoader]
        private void load(OverlayColourProvider colourProvider)
        {
            RelativeSizeAxes = Axes.X;
            AutoSizeAxes = Axes.Y;
            AddInternal(new GridContainer
            {
                RelativeSizeAxes = Axes.X,
                AutoSizeAxes = Axes.Y,
                ColumnDimensions = new[]
                {
                    new Dimension(GridSizeMode.Absolute, size: 28),
                    new Dimension(),
                    new Dimension(GridSizeMode.AutoSize)
                },
                RowDimensions = new[]
                {
                    new Dimension(GridSizeMode.AutoSize)
                },
                Content = new[]
                {
                    new Drawable[]
                    {
                        new Container
                        {
                            RelativeSizeAxes = Axes.X,
                            AutoSizeAxes = Axes.Y,
                            Child = createIcon().With(icon =>
                            {
                                icon.Anchor = Anchor.Centre;
                                icon.Origin = Anchor.Centre;
                            })
                        },
                        content = new LinkFlowContainer(t => t.Font = OsuFont.GetFont(size: font_size))
                        {
                            Anchor = Anchor.CentreLeft,
                            Origin = Anchor.CentreLeft,
                            AutoSizeAxes = Axes.Y,
                            RelativeSizeAxes = Axes.X,
                        },
                        new DrawableDate(activity.CreatedAt)
                        {
                            Anchor = Anchor.CentreRight,
                            Origin = Anchor.CentreRight,
                            Colour = colourProvider.Foreground1,
                            Font = OsuFont.GetFont(size: font_size),
                        }
                    }
                }
            });

            createMessage();
        }

        private Drawable createIcon()
        {
            switch (activity.Type)
            {
                case RecentActivityType.Rank:
                    return new UpdateableRank(activity.ScoreRank)
                    {
                        RelativeSizeAxes = Axes.X,
                        Height = 11,
                        FillMode = FillMode.Fit,
                        Margin = new MarginPadding { Top = 2 }
                    };

                case RecentActivityType.Achievement:
                    return new DelayedLoadWrapper(new MedalIcon(activity.Achievement.Slug)
                    {
                        Anchor = Anchor.Centre,
                        Origin = Anchor.Centre,
                        RelativeSizeAxes = Axes.Both,
                        FillMode = FillMode.Fit,
                    })
                    {
                        RelativeSizeAxes = Axes.X,
                        Width = 0.5f,
                        Height = 18
                    };

                default:
                    return new RecentActivityIcon(activity)
                    {
                        RelativeSizeAxes = Axes.X,
                        Height = 11,
                        FillMode = FillMode.Fit,
                        Margin = new MarginPadding { Top = 2, Vertical = 2 }
                    };
            }
        }

        private void createMessage()
        {
            switch (activity.Type)
            {
                case RecentActivityType.Achievement:
                    addUserLink();
                    addText($" unlocked the \"{activity.Achievement.Name}\" medal!");
                    break;

                case RecentActivityType.BeatmapPlaycount:
                    addBeatmapLink();
                    addText($" has been played {activity.Count} times!");
                    break;

                case RecentActivityType.BeatmapsetApprove:
                    addBeatmapsetLink();
                    addText($" has been {activity.Approval.ToString().ToLowerInvariant()}!");
                    break;

                case RecentActivityType.BeatmapsetDelete:
                    addBeatmapsetLink();
                    addText(" has been deleted.");
                    break;

                case RecentActivityType.BeatmapsetRevive:
                    addBeatmapsetLink();
                    addText(" has been revived from eternal slumber by ");
                    addUserLink();
                    break;

                case RecentActivityType.BeatmapsetUpdate:
                    addUserLink();
                    addText(" has updated the beatmap ");
                    addBeatmapsetLink();
                    break;

                case RecentActivityType.BeatmapsetUpload:
                    addUserLink();
                    addText(" has submitted a new beatmap ");
                    addBeatmapsetLink();
                    break;

                case RecentActivityType.Medal:
                    // apparently this shouldn't exist look at achievement instead (https://github.com/ppy/osu-web/blob/master/resources/assets/coffee/react/profile-page/recent-activity.coffee#L111)
                    break;

                case RecentActivityType.Rank:
                    addUserLink();
                    addText($" achieved rank #{activity.Rank} on ");
                    addBeatmapLink();
                    addText($" ({getRulesetName()})");
                    break;

                case RecentActivityType.RankLost:
                    addUserLink();
                    addText(" has lost first place on ");
                    addBeatmapLink();
                    addText($" ({getRulesetName()})");
                    break;

                case RecentActivityType.UserSupportAgain:
                    addUserLink();
                    addText(" has once again chosen to support osu! - thanks for your generosity!");
                    break;

                case RecentActivityType.UserSupportFirst:
                    addUserLink();
                    addText(" has become an osu!supporter - thanks for your generosity!");
                    break;

                case RecentActivityType.UserSupportGift:
                    addUserLink();
                    addText(" has received the gift of osu!supporter!");
                    break;

                case RecentActivityType.UsernameChange:
                    addText($"{activity.User?.PreviousUsername} has changed their username to ");
                    addUserLink();
                    break;
            }
        }

        private string getRulesetName() =>
            rulesets.AvailableRulesets.FirstOrDefault(r => r.ShortName == activity.Mode)?.Name ?? activity.Mode;

        private void addUserLink()
            => content.AddLink(activity.User.AsNonNull().Username, LinkAction.OpenUserProfile, getLinkArgument(activity.User.AsNonNull().Url), creationParameters: t => t.Font = getLinkFont(FontWeight.Bold));

        private void addBeatmapLink()
            => content.AddLink(activity.Beatmap.AsNonNull().Title, LinkAction.OpenBeatmap, getLinkArgument(activity.Beatmap.AsNonNull().Url), creationParameters: t => t.Font = getLinkFont());

        private void addBeatmapsetLink()
            => content.AddLink(activity.Beatmapset.AsNonNull().Title, LinkAction.OpenBeatmapSet, getLinkArgument(activity.Beatmapset.AsNonNull().Url), creationParameters: t => t.Font = getLinkFont());

        private object getLinkArgument(string url) => MessageFormatter.GetLinkDetails($"{api.Endpoints.WebsiteUrl}{url}").Argument.AsNonNull();

        private FontUsage getLinkFont(FontWeight fontWeight = FontWeight.Regular)
            => OsuFont.GetFont(size: font_size, weight: fontWeight, italics: true);

        private void addText(string text)
            => content.AddText(text, t => t.Font = OsuFont.GetFont(size: font_size, weight: FontWeight.SemiBold));
    }
}
