using System;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Dacryptero.Notifications;

namespace Dacryptero.Web.Events.Receive
{
    public class FileMove : ReceiveBase
    {
        public string Id { get; set; } = "";
        public string? Parent { get; set; }

        public override async Task Execute(ExecuteArgs args)
        {
            var id = Id.ToObjectId();
            var parent = Parent?.ToObjectId();

            if (id is null)
                return;
            
            var file = await args.Data.GetFileAsync(id, CancellationToken.None)
                .ConfigureAwait(false);
            if (file is null)
            {
                args.SendNotification(Notification.Error("Entry not found", ""));
                return;
            }

            if (file.Value.Value.ParentId == parent)
                return;

            var parentObj = parent is null ? null :
                await file.Value.Source.GetFileAsync(parent, CancellationToken.None)
                    .ConfigureAwait(false);
            if (parent is not null && parentObj is null)
            {
                args.SendNotification(Notification.Error("Parent not found", ""));
                return;
            }

            if (!await CheckParentage(file.Value.Source, file.Value.Value, parentObj?.Value))
            {
                args.SendNotification(Notification.Error(
                    "Move not allowed",
                    "Entry is not allowed to move in one of its children"
                ));
                return;
            }

            if (parentObj is not null &&
                parentObj.Value.Value.Confidential && !file.Value.Value.Confidential
            )
            {
                var mover = new FileChangeConfidential(Id, parentObj.Value.Value.Confidential);
                await mover.Execute(args).ConfigureAwait(false);
            }

            file.Value.Value.ParentId = parentObj?.Value.Id;
            await file.Value.Source.UpdateFile(file.Value.Value, CancellationToken.None)
                .ConfigureAwait(false);
            
            args.SendGlobalNotification(new Notification
            {
                Title = (file.Value.Value.Mime == "folder" ? "Folder" : "File") + " moved",
                Description = file.Value.Value.Name,
                Image = file.Value.Value.Mime == "folder"
                    ? "/img/svgrepo/interaction-set/folder-53011.svg"
                    : "/img/svgrepo/interaction-set/file-30366.svg",
                Close = DateTime.UtcNow.AddSeconds(5),
            });
            await WebSocketConnection.Foreach(async con =>
            {
                await con.Send(new Send.FileMoved(file.Value))
                    .ConfigureAwait(false);
            }).ConfigureAwait(false);
        }

        private async Task<bool> CheckParentage(DB.DBSingleController db, Data.File file, Data.File? parent)
        {
            while (parent is not null)
            {
                if (parent.Id == file.Id)
                    return false;
                parent = parent.ParentId is null ? null :
                    (await db.GetFileAsync(parent.ParentId, CancellationToken.None)
                        .ConfigureAwait(false)
                    )?.Value;
            }
            return true;
        }

        public override void ReadJsonContent(JsonElement json)
        {
            Id = json.GetProperty("id").GetString() ?? "";
            Parent = json.GetProperty("parent").GetString();
        }
    }
}