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

namespace Dacryptero.Web.Events.Receive
{
    public class EditPersonSend : ReceiveBase
    {
        public string Id { get; private set; } = "";

        public bool Delete { get; private set; }

        public string? Name { get; private set; }

        public string? Contact { get; private set; }

        public override async Task Execute(ExecuteArgs args)
        {
            var id = Id.ToObjectId();
            if (id is null)
            {
                await args.Connection.Send(new Send.EditDenied(Id, null,
                    Send.EditTarget.Person, Send.EditDeniedReason.IdNotFound,
                    "invalid id"
                )).ConfigureAwait(false);
                return;
            }
            var result = await args.Data.GetPersonAsync(id, CancellationToken.None)
                .ConfigureAwait(false);
            if (result is null)
            {
                await args.Connection.Send(new Send.EditDenied(Id, null,
                    Send.EditTarget.Person, Send.EditDeniedReason.IdNotFound,
                    "id does not exists"
                )).ConfigureAwait(false);
                return;
            }
            var person = result.Value.Value;
            if (person.Deleted)
            {
                await args.Connection.Send(new Send.EditDenied(Id, null,
                    Send.EditTarget.Person, Send.EditDeniedReason.Generic,
                    "person is deleted"
                )).ConfigureAwait(false);
                return;
            }
            if (person.ConfData is not null)
            {
                if (Name is not null)
                {
                    result.Value.Source.ReplaceIndex(Data.IndexSource.Persons, id, person.ConfData.Name, Name, true, args);
                    person.ConfData.Name = Name;
                    await args.Connection.Send(new Send.EditAccept(Id, "name", Send.EditTarget.Person))
                        .ConfigureAwait(false);
                }
                if (Contact is not null)
                {
                    result.Value.Source.ReplaceIndex(Data.IndexSource.Persons, id, person.ConfData.Contact, Contact, true, args);
                    person.ConfData.Contact = Contact;
                    await args.Connection.Send(new Send.EditAccept(Id, "contact", Send.EditTarget.Person))
                        .ConfigureAwait(false);
                }
            }
            result.Value.Value.Deleted = Delete;
            var status = await result.Value.Source.UpdatePersonAsync(result.Value.Value, CancellationToken.None)
                .ConfigureAwait(false);
            if (Delete)
            {
                if (person.ConfData is not null)
                {
                    var interview = await result.Value.Source.GetInterviewAsync(person.ConfData.Interview.Id, CancellationToken.None)
                        .ConfigureAwait(false);
                    if (interview is not null)
                    {
                        interview.Value.Value.Person.Remove(person.Id);
                        await result.Value.Source.UpdateInterviewAsync(interview.Value.Value, CancellationToken.None)
                            .ConfigureAwait(false);
                    }
                }

                person.PerformIndex(result.Value.Source, true, false, args);

                args.SendGlobalNotification(new Notification
                {
                    Image = "/img/svgrepo/essential-set-2/garbage-51844.svg",
                    Title = "Person deleted",
                    Description = $"{person.ConfData?.Name ?? person.Id.ToString()} deleted",
                    Close = System.DateTime.UtcNow.AddSeconds(15),
                });
            }
            await args.Connection.Send(new Send.EditAccept(Id, null, Send.EditTarget.Person))
                .ConfigureAwait(false);
        }

        public override void ReadJsonContent(JsonElement json)
        {
            Id = json.GetProperty("id").GetString() ?? "";
            Delete = json.GetProperty("delete").GetBoolean();
            Name = json.TryGetProperty("name", out JsonElement node) ?
                node.GetString() : null;
            Contact = json.TryGetProperty("contact", out node) ?
                node.GetString() : null;
        }
    }
}