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.RealmsScreen;
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 me, final Minecraft dlx, @Nullable final Screen dqs, final Consumer<Component> consumer) {
        this.connection = me;
        this.minecraft = dlx;
        this.parent = dqs;
        this.updateStatus = consumer;
    }
    
    @Override
    public void handleHello(final ClientboundHelloPacket sz) {
        final SecretKey secretKey3 = Crypt.generateSecretKey();
        final PublicKey publicKey4 = sz.getPublicKey();
        final String string5 = new BigInteger(Crypt.digestData(sz.getServerId(), publicKey4, secretKey3)).toString(16);
        final ServerboundKeyPacket tf6 = new ServerboundKeyPacket(secretKey3, publicKey4, sz.getNonce());
        this.updateStatus.accept(new TranslatableComponent("connect.authorizing"));
        final String string6;
        final Component mr5;
        final Packet<?> ni;
        final Object o;
        HttpUtil.DOWNLOAD_EXECUTOR.submit(() -> {
            mr5 = this.authenticateServer(string6);
            if (mr5 != null) {
                if (this.minecraft.getCurrentServer() != null && this.minecraft.getCurrentServer().isLan()) {
                    ClientHandshakePacketListenerImpl.LOGGER.warn(mr5.getString());
                }
                else {
                    this.connection.disconnect(mr5);
                    return;
                }
            }
            this.updateStatus.accept(new TranslatableComponent("connect.encrypting"));
            this.connection.send(ni, (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") });
        }
        catch (InvalidCredentialsException invalidCredentialsException3) {
            return new TranslatableComponent("disconnect.loginFailedInfo", new Object[] { new TranslatableComponent("disconnect.loginFailedInfo.invalidSession") });
        }
        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 sy) {
        this.updateStatus.accept(new TranslatableComponent("connect.joining"));
        this.localGameProfile = sy.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 mr) {
        if (this.parent != null && this.parent instanceof RealmsScreen) {
            this.minecraft.setScreen(new DisconnectedRealmsScreen(this.parent, "connect.failed", mr));
        }
        else {
            this.minecraft.setScreen(new DisconnectedScreen(this.parent, "connect.failed", mr));
        }
    }
    
    @Override
    public Connection getConnection() {
        return this.connection;
    }
    
    @Override
    public void handleDisconnect(final ClientboundLoginDisconnectPacket tb) {
        this.connection.disconnect(tb.getReason());
    }
    
    @Override
    public void handleCompression(final ClientboundLoginCompressionPacket ta) {
        if (!this.connection.isMemoryConnection()) {
            this.connection.setupCompression(ta.getCompressionThreshold());
        }
    }
    
    @Override
    public void handleCustomQuery(final ClientboundCustomQueryPacket sx) {
        this.updateStatus.accept(new TranslatableComponent("connect.negotiating"));
        this.connection.send(new ServerboundCustomQueryPacket(sx.getTransactionId(), null));
    }
    
    static {
        LOGGER = LogManager.getLogger();
    }
}
