package com.mojang.realmsclient.gui.screens;

import org.apache.logging.log4j.LogManager;
import java.util.concurrent.TimeUnit;
import net.minecraft.Util;
import com.mojang.blaze3d.vertex.BufferBuilder;
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
import com.mojang.blaze3d.vertex.Tesselator;
import com.mojang.blaze3d.systems.RenderSystem;
import java.util.Locale;
import net.minecraft.network.chat.FormattedText;
import com.mojang.blaze3d.vertex.PoseStack;
import java.util.List;
import net.minecraft.realms.NarrationHelper;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.function.Function;
import net.minecraft.network.chat.TextComponent;
import com.google.common.collect.Lists;
import com.mojang.realmsclient.client.FileDownload;
import com.mojang.realmsclient.Unit;
import net.minecraft.network.chat.CommonComponents;
import net.minecraft.network.chat.TranslatableComponent;
import it.unimi.dsi.fastutil.booleans.BooleanConsumer;
import net.minecraft.client.gui.components.Button;
import com.google.common.util.concurrent.RateLimiter;
import net.minecraft.network.chat.Component;
import com.mojang.realmsclient.dto.WorldDownload;
import net.minecraft.client.gui.screens.Screen;
import java.util.concurrent.locks.ReentrantLock;
import org.apache.logging.log4j.Logger;
import net.minecraft.realms.RealmsScreen;

public class RealmsDownloadLatestWorldScreen extends RealmsScreen {
    private static final Logger LOGGER;
    private static final ReentrantLock DOWNLOAD_LOCK;
    private final Screen lastScreen;
    private final WorldDownload worldDownload;
    private final Component downloadTitle;
    private final RateLimiter narrationRateLimiter;
    private Button cancelButton;
    private final String worldName;
    private final DownloadStatus downloadStatus;
    private volatile Component errorMessage;
    private volatile Component status;
    private volatile String progress;
    private volatile boolean cancelled;
    private volatile boolean showDots;
    private volatile boolean finished;
    private volatile boolean extracting;
    private Long previousWrittenBytes;
    private Long previousTimeSnapshot;
    private long bytesPersSecond;
    private int animTick;
    private static final String[] DOTS;
    private int dotIndex;
    private boolean checked;
    private final BooleanConsumer callback;
    
    public RealmsDownloadLatestWorldScreen(final Screen dqs, final WorldDownload djc, final String string, final BooleanConsumer booleanConsumer) {
        this.status = new TranslatableComponent("mco.download.preparing");
        this.showDots = true;
        this.callback = booleanConsumer;
        this.lastScreen = dqs;
        this.worldName = string;
        this.worldDownload = djc;
        this.downloadStatus = new DownloadStatus();
        this.downloadTitle = new TranslatableComponent("mco.download.title");
        this.narrationRateLimiter = RateLimiter.create(0.10000000149011612);
    }
    
    public void init() {
        this.minecraft.keyboardHandler.setSendRepeatsToGui(true);
        this.cancelButton = this.<Button>addButton(new Button(this.width / 2 - 100, this.height - 42, 200, 20, CommonComponents.GUI_CANCEL, dni -> {
            this.cancelled = true;
            this.backButtonClicked();
            return;
        }));
        this.checkDownloadSize();
    }
    
    private void checkDownloadSize() {
        if (this.finished) {
            return;
        }
        if (!this.checked && this.getContentLength(this.worldDownload.downloadLink) >= 5368709120L) {
            final Component mr2 = new TranslatableComponent("mco.download.confirmation.line1", new Object[] { Unit.humanReadable(5368709120L) });
            final Component mr3 = new TranslatableComponent("mco.download.confirmation.line2");
            this.minecraft.setScreen(new RealmsLongConfirmationScreen(boolean1 -> {
                this.checked = true;
                this.minecraft.setScreen(this);
                this.downloadSave();
            }, RealmsLongConfirmationScreen.Type.Warning, mr2, mr3, false));
        }
        else {
            this.downloadSave();
        }
    }
    
    private long getContentLength(final String string) {
        final FileDownload dhx3 = new FileDownload();
        return dhx3.contentLength(string);
    }
    
    @Override
    public void tick() {
        super.tick();
        ++this.animTick;
        if (this.status != null && this.narrationRateLimiter.tryAcquire(1)) {
            final List<Component> list2 = Lists.newArrayList();
            list2.add(this.downloadTitle);
            list2.add(this.status);
            if (this.progress != null) {
                list2.add(new TextComponent(this.progress + "%"));
                list2.add(new TextComponent(Unit.humanReadable(this.bytesPersSecond) + "/s"));
            }
            if (this.errorMessage != null) {
                list2.add(this.errorMessage);
            }
            final String string3 = list2.stream().map(Component::getString).collect(Collectors.joining("\n"));
            NarrationHelper.now(string3);
        }
    }
    
    @Override
    public boolean keyPressed(final int integer1, final int integer2, final int integer3) {
        if (integer1 == 256) {
            this.cancelled = true;
            this.backButtonClicked();
            return true;
        }
        return super.keyPressed(integer1, integer2, integer3);
    }
    
    private void backButtonClicked() {
        if (this.finished && this.callback != null && this.errorMessage == null) {
            this.callback.accept(true);
        }
        this.minecraft.setScreen(this.lastScreen);
    }
    
    @Override
    public void render(final PoseStack dhl, final int integer2, final int integer3, final float float4) {
        this.renderBackground(dhl);
        if (this.extracting && !this.finished) {
            this.status = new TranslatableComponent("mco.download.extracting");
        }
        this.drawCenteredString(dhl, this.font, this.downloadTitle, this.width / 2, 20, 16777215);
        this.drawCenteredString(dhl, this.font, this.status, this.width / 2, 50, 16777215);
        if (this.showDots) {
            this.drawDots(dhl);
        }
        if (this.downloadStatus.bytesWritten != 0L && !this.cancelled) {
            this.drawProgressBar(dhl);
            this.drawDownloadSpeed(dhl);
        }
        if (this.errorMessage != null) {
            this.drawCenteredString(dhl, this.font, this.errorMessage, this.width / 2, 110, 16711680);
        }
        super.render(dhl, integer2, integer3, float4);
    }
    
    private void drawDots(final PoseStack dhl) {
        final int integer3 = this.font.width(this.status);
        if (this.animTick % 10 == 0) {
            ++this.dotIndex;
        }
        this.font.draw(dhl, RealmsDownloadLatestWorldScreen.DOTS[this.dotIndex % RealmsDownloadLatestWorldScreen.DOTS.length], (float)(this.width / 2 + integer3 / 2 + 5), 50.0f, 16777215);
    }
    
    private void drawProgressBar(final PoseStack dhl) {
        final double double3 = this.downloadStatus.bytesWritten / (double)this.downloadStatus.totalBytes * 100.0;
        this.progress = String.format(Locale.ROOT, "%.1f", double3);
        RenderSystem.color4f(1.0f, 1.0f, 1.0f, 1.0f);
        RenderSystem.disableTexture();
        final Tesselator dhn5 = Tesselator.getInstance();
        final BufferBuilder dhg6 = dhn5.getBuilder();
        dhg6.begin(7, DefaultVertexFormat.POSITION_COLOR);
        final double double4 = this.width / 2 - 100;
        final double double5 = 0.5;
        dhg6.vertex(double4 - 0.5, 95.5, 0.0).color(217, 210, 210, 255).endVertex();
        dhg6.vertex(double4 + 200.0 * double3 / 100.0 + 0.5, 95.5, 0.0).color(217, 210, 210, 255).endVertex();
        dhg6.vertex(double4 + 200.0 * double3 / 100.0 + 0.5, 79.5, 0.0).color(217, 210, 210, 255).endVertex();
        dhg6.vertex(double4 - 0.5, 79.5, 0.0).color(217, 210, 210, 255).endVertex();
        dhg6.vertex(double4, 95.0, 0.0).color(128, 128, 128, 255).endVertex();
        dhg6.vertex(double4 + 200.0 * double3 / 100.0, 95.0, 0.0).color(128, 128, 128, 255).endVertex();
        dhg6.vertex(double4 + 200.0 * double3 / 100.0, 80.0, 0.0).color(128, 128, 128, 255).endVertex();
        dhg6.vertex(double4, 80.0, 0.0).color(128, 128, 128, 255).endVertex();
        dhn5.end();
        RenderSystem.enableTexture();
        this.drawCenteredString(dhl, this.font, this.progress + " %", this.width / 2, 84, 16777215);
    }
    
    private void drawDownloadSpeed(final PoseStack dhl) {
        if (this.animTick % 20 == 0) {
            if (this.previousWrittenBytes != null) {
                long long3 = Util.getMillis() - this.previousTimeSnapshot;
                if (long3 == 0L) {
                    long3 = 1L;
                }
                this.drawDownloadSpeed0(dhl, this.bytesPersSecond = 1000L * (this.downloadStatus.bytesWritten - this.previousWrittenBytes) / long3);
            }
            this.previousWrittenBytes = this.downloadStatus.bytesWritten;
            this.previousTimeSnapshot = Util.getMillis();
        }
        else {
            this.drawDownloadSpeed0(dhl, this.bytesPersSecond);
        }
    }
    
    private void drawDownloadSpeed0(final PoseStack dhl, final long long2) {
        if (long2 > 0L) {
            final int integer5 = this.font.width(this.progress);
            final String string6 = "(" + Unit.humanReadable(long2) + "/s)";
            this.font.draw(dhl, string6, (float)(this.width / 2 + integer5 / 2 + 15), 84.0f, 16777215);
        }
    }
    
    private void downloadSave() {
        final TranslatableComponent status;
        FileDownload dhx2;
        new Thread(() -> {
            try {
                if (!RealmsDownloadLatestWorldScreen.DOWNLOAD_LOCK.tryLock(1L, TimeUnit.SECONDS)) {
                    this.status = new TranslatableComponent("mco.download.failed");
                }
                else if (this.cancelled) {
                    this.downloadCancelled();
                }
                else {
                    new TranslatableComponent("mco.download.downloading", new Object[] { this.worldName });
                    this.status = status;
                    dhx2 = new FileDownload();
                    dhx2.contentLength(this.worldDownload.downloadLink);
                    dhx2.download(this.worldDownload, this.worldName, this.downloadStatus, this.minecraft.getLevelSource());
                    while (!dhx2.isFinished()) {
                        if (dhx2.isError()) {
                            dhx2.cancel();
                            this.errorMessage = new TranslatableComponent("mco.download.failed");
                            this.cancelButton.setMessage(CommonComponents.GUI_DONE);
                            return;
                        }
                        else {
                            if (dhx2.isExtracting()) {
                                this.extracting = true;
                            }
                            if (this.cancelled) {
                                dhx2.cancel();
                                this.downloadCancelled();
                                return;
                            }
                            else {
                                try {
                                    Thread.sleep(500L);
                                }
                                catch (InterruptedException interruptedException3) {
                                    RealmsDownloadLatestWorldScreen.LOGGER.error("Failed to check Realms backup download status");
                                }
                            }
                        }
                    }
                    this.finished = true;
                    this.status = new TranslatableComponent("mco.download.done");
                    this.cancelButton.setMessage(CommonComponents.GUI_DONE);
                }
            }
            catch (InterruptedException interruptedException4) {
                RealmsDownloadLatestWorldScreen.LOGGER.error("Could not acquire upload lock");
            }
            catch (Exception exception2) {
                this.errorMessage = new TranslatableComponent("mco.download.failed");
                exception2.printStackTrace();
            }
            finally {
                if (RealmsDownloadLatestWorldScreen.DOWNLOAD_LOCK.isHeldByCurrentThread()) {
                    RealmsDownloadLatestWorldScreen.DOWNLOAD_LOCK.unlock();
                    this.showDots = false;
                    this.finished = true;
                }
            }
        }).start();
    }
    
    private void downloadCancelled() {
        this.status = new TranslatableComponent("mco.download.cancelled");
    }
    
    static {
        LOGGER = LogManager.getLogger();
        DOWNLOAD_LOCK = new ReentrantLock();
        DOTS = new String[] { "", ".", ". .", ". . ." };
    }
    
    public class DownloadStatus {
        public volatile Long bytesWritten;
        public volatile Long totalBytes;
        
        public DownloadStatus() {
            this.bytesWritten = 0L;
            this.totalBytes = 0L;
        }
    }
}
