/*
 * Copyright 2015 Austin Keener, Michael Ritter, Florian Spieß, and the JDA contributors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package net.dv8tion.jda.internal.interactions;

import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.entities.*;
import net.dv8tion.jda.api.interactions.Interaction;
import net.dv8tion.jda.api.utils.data.DataObject;
import net.dv8tion.jda.internal.JDAImpl;
import net.dv8tion.jda.internal.entities.GuildImpl;
import net.dv8tion.jda.internal.entities.MemberImpl;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Locale;

public class InteractionImpl implements Interaction
{
    protected final long id;
    protected final int type;
    protected final String token;
    protected final Guild guild;
    protected final Member member;
    protected final User user;
    protected final Channel channel;
    protected final Locale userLocale;
    protected final JDAImpl api;

    //This is used to give a proper error when an interaction is ack'd twice
    // By default, discord only responds with "unknown interaction" which is horrible UX so we add a check manually here
    private boolean isAck;

    public InteractionImpl(JDAImpl jda, DataObject data)
    {
        this.api = jda;
        this.id = data.getUnsignedLong("id");
        this.token = data.getString("token");
        this.type = data.getInt("type");
        this.guild = jda.getGuildById(data.getUnsignedLong("guild_id", 0L));
        this.userLocale = Locale.forLanguageTag(data.getString("locale", "en-US"));
        if (guild != null)
        {
            member = jda.getEntityBuilder().createMember((GuildImpl) guild, data.getObject("member"));
            jda.getEntityBuilder().updateMemberCache((MemberImpl) member);
            user = member.getUser();
            channel = guild.getGuildChannelById(data.getUnsignedLong("channel_id"));
        }
        else
        {
            member = null;
            long channelId = data.getUnsignedLong("channel_id");
            PrivateChannel channel = jda.getPrivateChannelById(channelId);
            if (channel == null)
            {
                channel = jda.getEntityBuilder().createPrivateChannel(
                    DataObject.empty()
                        .put("id", channelId)
                        .put("recipient", data.getObject("user"))
                );
            }
            this.channel = channel;
            user = channel.getUser();
        }
    }

    public synchronized boolean ack()
    {
        boolean wasAck = isAck;
        this.isAck = true;
        return wasAck;
    }

    @Override
    public synchronized boolean isAcknowledged()
    {
        return isAck;
    }

    @Override
    public long getIdLong()
    {
        return id;
    }

    @Override
    public int getTypeRaw()
    {
        return type;
    }

    @Nonnull
    @Override
    public String getToken()
    {
        return token;
    }

    @Nullable
    @Override
    public Guild getGuild()
    {
        return guild;
    }

    @Nullable
    @Override
    public Channel getChannel()
    {
        return channel;
    }

    @Nonnull
    public Locale getUserLocale()
    {
        return userLocale;
    }

    @Nonnull
    @Override
    public User getUser()
    {
        return user;
    }

    @Nullable
    @Override
    public Member getMember()
    {
        return member;
    }

    @Nonnull
    @Override
    public JDA getJDA()
    {
        return api;
    }
}

@@ -1014,16 +1014,128 @@
 berImpl;
+%0Aimport net.dv8tion.jda.internal.entities.PrivateChannelImpl;%0Aimport net.dv8tion.jda.internal.entities.UserImpl;
 %0A%0Aimport
@@ -3055,24 +3055,25 @@
  = channel;%0A
+%0A
             
@@ -3068,24 +3068,29 @@
             
+User 
 user = chann
@@ -3095,32 +3095,326 @@
 nnel.getUser();%0A
+            if (user == null)%0A            %7B%0A                user = jda.getEntityBuilder().createUser(data.getObject(%22user%22));%0A                ((PrivateChannelImpl) channel).setUser(user);%0A                ((UserImpl) user).setPrivateChannel(channel);%0A            %7D%0A            this.user = user;%0A
         %7D%0A    %7D%0A

Build the User from data in the Interaction if the User was not cached. (#2060)