package net.minecraft.client.multiplayer;

import org.apache.logging.log4j.LogManager;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.protocol.login.ServerboundCustomQueryPacket;
import net.minecraft.network.protocol.login.ClientboundCustomQueryPacket;
import net.minecraft.network.protocol.login.ClientboundLoginCompressionPacket;
import net.minecraft.network.protocol.login.ClientboundLoginDisconnectPacket;
import net.minecraft.client.gui.screens.DisconnectedScreen;
import net.minecraft.realms.DisconnectedRealmsScreen;
import net.minecraft.realms.RealmsScreenProxy;
import net.minecraft.network.PacketListener;
import net.minecraft.network.ConnectionProtocol;
import net.minecraft.network.protocol.login.ClientboundGameProfilePacket;
import com.mojang.authlib.minecraft.MinecraftSessionService;
import com.mojang.authlib.exceptions.AuthenticationException;
import com.mojang.authlib.exceptions.InvalidCredentialsException;
import com.mojang.authlib.exceptions.AuthenticationUnavailableException;
import net.minecraft.network.protocol.Packet;
import java.security.PublicKey;
import javax.crypto.SecretKey;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
import net.minecraft.util.HttpUtil;
import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.network.protocol.login.ServerboundKeyPacket;
import java.math.BigInteger;
import net.minecraft.util.Crypt;
import net.minecraft.network.protocol.login.ClientboundHelloPacket;
import com.mojang.authlib.GameProfile;
import net.minecraft.network.Connection;
import net.minecraft.network.chat.Component;
import java.util.function.Consumer;
import javax.annotation.Nullable;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.Minecraft;
import org.apache.logging.log4j.Logger;
import net.minecraft.network.protocol.login.ClientLoginPacketListener;

public class ClientHandshakePacketListenerImpl implements ClientLoginPacketListener {
    private static final Logger LOGGER;
    private final Minecraft minecraft;
    @Nullable
    private final Screen parent;
    private final Consumer<Component> updateStatus;
    private final Connection connection;
    private GameProfile localGameProfile;
    
    public ClientHandshakePacketListenerImpl(final Connection kt, final Minecraft dbn, @Nullable final Screen dgb, final Consumer<Component> consumer) {
        this.connection = kt;
        this.minecraft = dbn;
        this.parent = dgb;
        this.updateStatus = consumer;
    }
    
    @Override
    public void handleHello(final ClientboundHelloPacket rk) {
        final SecretKey secretKey3 = Crypt.generateSecretKey();
        final PublicKey publicKey4 = rk.getPublicKey();
        final String string5 = new BigInteger(Crypt.digestData(rk.getServerId(), publicKey4, secretKey3)).toString(16);
        final ServerboundKeyPacket rq6 = new ServerboundKeyPacket(secretKey3, publicKey4, rk.getNonce());
        this.updateStatus.accept(new TranslatableComponent("connect.authorizing", new Object[0]));
        final String string6;
        final Component lf5;
        final Packet<?> lt;
        final Object o;
        HttpUtil.DOWNLOAD_EXECUTOR.submit(() -> {
            lf5 = this.authenticateServer(string6);
            if (lf5 != null) {
                if (this.minecraft.getCurrentServer() != null && this.minecraft.getCurrentServer().isLan()) {
                    ClientHandshakePacketListenerImpl.LOGGER.warn(lf5.getString());
                }
                else {
                    this.connection.disconnect(lf5);
                    return;
                }
            }
            this.updateStatus.accept(new TranslatableComponent("connect.encrypting", new Object[0]));
            this.connection.send(lt, (future -> this.connection.setEncryptionKey(o)));
        });
    }
    
    @Nullable
    private Component authenticateServer(final String string) {
        try {
            this.getMinecraftSessionService().joinServer(this.minecraft.getUser().getGameProfile(), this.minecraft.getUser().getAccessToken(), string);
        }
        catch (AuthenticationUnavailableException authenticationUnavailableException3) {
            return new TranslatableComponent("disconnect.loginFailedInfo", new Object[] { new TranslatableComponent("disconnect.loginFailedInfo.serversUnavailable", new Object[0]) });
        }
        catch (InvalidCredentialsException invalidCredentialsException3) {
            return new TranslatableComponent("disconnect.loginFailedInfo", new Object[] { new TranslatableComponent("disconnect.loginFailedInfo.invalidSession", new Object[0]) });
        }
        catch (AuthenticationException authenticationException3) {
            return new TranslatableComponent("disconnect.loginFailedInfo", new Object[] { authenticationException3.getMessage() });
        }
        return null;
    }
    
    private MinecraftSessionService getMinecraftSessionService() {
        return this.minecraft.getMinecraftSessionService();
    }
    
    @Override
    public void handleGameProfile(final ClientboundGameProfilePacket rj) {
        this.updateStatus.accept(new TranslatableComponent("connect.joining", new Object[0]));
        this.localGameProfile = rj.getGameProfile();
        this.connection.setProtocol(ConnectionProtocol.PLAY);
        this.connection.setListener(new ClientPacketListener(this.minecraft, this.parent, this.connection, this.localGameProfile));
    }
    
    @Override
    public void onDisconnect(final Component lf) {
        if (this.parent != null && this.parent instanceof RealmsScreenProxy) {
            this.minecraft.setScreen(new DisconnectedRealmsScreen(((RealmsScreenProxy)this.parent).getScreen(), "connect.failed", lf).getProxy());
        }
        else {
            this.minecraft.setScreen(new DisconnectedScreen(this.parent, "connect.failed", lf));
        }
    }
    
    @Override
    public Connection getConnection() {
        return this.connection;
    }
    
    @Override
    public void handleDisconnect(final ClientboundLoginDisconnectPacket rm) {
        this.connection.disconnect(rm.getReason());
    }
    
    @Override
    public void handleCompression(final ClientboundLoginCompressionPacket rl) {
        if (!this.connection.isMemoryConnection()) {
            this.connection.setupCompression(rl.getCompressionThreshold());
        }
    }
    
    @Override
    public void handleCustomQuery(final ClientboundCustomQueryPacket ri) {
        this.updateStatus.accept(new TranslatableComponent("connect.negotiating", new Object[0]));
        this.connection.send(new ServerboundCustomQueryPacket(ri.getTransactionId(), null));
    }
    
    static {
        LOGGER = LogManager.getLogger();
    }
}
