package com.mojang.realmsclient.gui.screens;

import org.apache.logging.log4j.LogManager;
import java.util.concurrent.TimeUnit;
import net.minecraft.realms.RealmsDefaultVertexFormat;
import net.minecraft.realms.Tezzelator;
import com.mojang.blaze3d.systems.RenderSystem;
import java.util.Locale;
import java.util.List;
import com.google.common.collect.Lists;
import com.mojang.realmsclient.client.FileDownload;
import net.minecraft.realms.Realms;
import net.minecraft.realms.RealmsConfirmResultListener;
import net.minecraft.realms.AbstractRealmsButton;
import java.util.concurrent.locks.ReentrantLock;
import net.minecraft.realms.RealmsButton;
import com.google.common.util.concurrent.RateLimiter;
import com.mojang.realmsclient.dto.WorldDownload;
import org.apache.logging.log4j.Logger;
import net.minecraft.realms.RealmsScreen;

public class RealmsDownloadLatestWorldScreen extends RealmsScreen {
    private static final Logger LOGGER;
    private final RealmsScreen lastScreen;
    private final WorldDownload worldDownload;
    private final String downloadTitle;
    private final RateLimiter narrationRateLimiter;
    private RealmsButton cancelButton;
    private final String worldName;
    private final DownloadStatus downloadStatus;
    private volatile String errorMessage;
    private volatile String 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 final int WARNING_ID = 100;
    private int confirmationId;
    private boolean checked;
    private static final ReentrantLock downloadLock;
    
    public RealmsDownloadLatestWorldScreen(final RealmsScreen realmsScreen, final WorldDownload worldDownload, final String string) {
        this.showDots = true;
        this.confirmationId = -1;
        this.lastScreen = realmsScreen;
        this.worldName = string;
        this.worldDownload = worldDownload;
        this.downloadStatus = new DownloadStatus();
        this.downloadTitle = RealmsScreen.getLocalizedString("mco.download.title");
        this.narrationRateLimiter = RateLimiter.create(0.10000000149011612);
    }
    
    public void setConfirmationId(final int integer) {
        this.confirmationId = integer;
    }
    
    @Override
    public void init() {
        this.setKeyboardHandlerSendRepeatsToGui(true);
        this.buttonsAdd(this.cancelButton = new RealmsButton(0, this.width() / 2 - 100, this.height() - 42, 200, 20, RealmsScreen.getLocalizedString("gui.cancel")) {
            @Override
            public void onPress() {
                RealmsDownloadLatestWorldScreen.this.cancelled = true;
                RealmsDownloadLatestWorldScreen.this.backButtonClicked();
            }
        });
        this.checkDownloadSize();
    }
    
    private void checkDownloadSize() {
        if (this.finished) {
            return;
        }
        if (!this.checked && this.getContentLength(this.worldDownload.downloadLink) >= 5368709120L) {
            final String string2 = RealmsScreen.getLocalizedString("mco.download.confirmation.line1", humanReadableSize(5368709120L));
            final String string3 = RealmsScreen.getLocalizedString("mco.download.confirmation.line2");
            Realms.setScreen(new RealmsLongConfirmationScreen(this, RealmsLongConfirmationScreen.Type.Warning, string2, string3, false, 100));
        }
        else {
            this.downloadSave();
        }
    }
    
    @Override
    public void confirmResult(final boolean boolean1, final int integer) {
        this.checked = true;
        Realms.setScreen(this);
        this.downloadSave();
    }
    
    private long getContentLength(final String string) {
        final FileDownload cyv3 = new FileDownload();
        return cyv3.contentLength(string);
    }
    
    @Override
    public void tick() {
        super.tick();
        ++this.animTick;
        if (this.status != null && this.narrationRateLimiter.tryAcquire(1)) {
            final List<String> list2 = Lists.newArrayList();
            list2.add(this.downloadTitle);
            list2.add(this.status);
            if (this.progress != null) {
                list2.add(this.progress + "%");
                list2.add(humanReadableSpeed(this.bytesPersSecond));
            }
            if (this.errorMessage != null) {
                list2.add(this.errorMessage);
            }
            final String string3 = String.join(System.lineSeparator(), list2);
            Realms.narrateNow(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.confirmationId != -1 && this.errorMessage == null) {
            this.lastScreen.confirmResult(true, this.confirmationId);
        }
        Realms.setScreen(this.lastScreen);
    }
    
    @Override
    public void render(final int integer1, final int integer2, final float float3) {
        this.renderBackground();
        if (this.extracting && !this.finished) {
            this.status = RealmsScreen.getLocalizedString("mco.download.extracting");
        }
        this.drawCenteredString(this.downloadTitle, this.width() / 2, 20, 16777215);
        this.drawCenteredString(this.status, this.width() / 2, 50, 16777215);
        if (this.showDots) {
            this.drawDots();
        }
        if (this.downloadStatus.bytesWritten != 0L && !this.cancelled) {
            this.drawProgressBar();
            this.drawDownloadSpeed();
        }
        if (this.errorMessage != null) {
            this.drawCenteredString(this.errorMessage, this.width() / 2, 110, 16711680);
        }
        super.render(integer1, integer2, float3);
    }
    
    private void drawDots() {
        final int integer2 = this.fontWidth(this.status);
        if (this.animTick % 10 == 0) {
            ++this.dotIndex;
        }
        this.drawString(RealmsDownloadLatestWorldScreen.DOTS[this.dotIndex % RealmsDownloadLatestWorldScreen.DOTS.length], this.width() / 2 + integer2 / 2 + 5, 50, 16777215);
    }
    
    private void drawProgressBar() {
        final double double2 = this.downloadStatus.bytesWritten / (double)this.downloadStatus.totalBytes * 100.0;
        this.progress = String.format(Locale.ROOT, "%.1f", double2);
        RenderSystem.color4f(1.0f, 1.0f, 1.0f, 1.0f);
        RenderSystem.disableTexture();
        final Tezzelator tezzelator4 = Tezzelator.instance;
        tezzelator4.begin(7, RealmsDefaultVertexFormat.POSITION_COLOR);
        final double double3 = this.width() / 2 - 100;
        final double double4 = 0.5;
        tezzelator4.vertex(double3 - 0.5, 95.5, 0.0).color(217, 210, 210, 255).endVertex();
        tezzelator4.vertex(double3 + 200.0 * double2 / 100.0 + 0.5, 95.5, 0.0).color(217, 210, 210, 255).endVertex();
        tezzelator4.vertex(double3 + 200.0 * double2 / 100.0 + 0.5, 79.5, 0.0).color(217, 210, 210, 255).endVertex();
        tezzelator4.vertex(double3 - 0.5, 79.5, 0.0).color(217, 210, 210, 255).endVertex();
        tezzelator4.vertex(double3, 95.0, 0.0).color(128, 128, 128, 255).endVertex();
        tezzelator4.vertex(double3 + 200.0 * double2 / 100.0, 95.0, 0.0).color(128, 128, 128, 255).endVertex();
        tezzelator4.vertex(double3 + 200.0 * double2 / 100.0, 80.0, 0.0).color(128, 128, 128, 255).endVertex();
        tezzelator4.vertex(double3, 80.0, 0.0).color(128, 128, 128, 255).endVertex();
        tezzelator4.end();
        RenderSystem.enableTexture();
        this.drawCenteredString(this.progress + " %", this.width() / 2, 84, 16777215);
    }
    
    private void drawDownloadSpeed() {
        if (this.animTick % 20 == 0) {
            if (this.previousWrittenBytes != null) {
                long long2 = System.currentTimeMillis() - this.previousTimeSnapshot;
                if (long2 == 0L) {
                    long2 = 1L;
                }
                this.drawDownloadSpeed0(this.bytesPersSecond = 1000L * (this.downloadStatus.bytesWritten - this.previousWrittenBytes) / long2);
            }
            this.previousWrittenBytes = this.downloadStatus.bytesWritten;
            this.previousTimeSnapshot = System.currentTimeMillis();
        }
        else {
            this.drawDownloadSpeed0(this.bytesPersSecond);
        }
    }
    
    private void drawDownloadSpeed0(final long long1) {
        if (long1 > 0L) {
            final int integer4 = this.fontWidth(this.progress);
            final String string5 = "(" + humanReadableSpeed(long1) + ")";
            this.drawString(string5, this.width() / 2 + integer4 / 2 + 15, 84, 16777215);
        }
    }
    
    public static String humanReadableSpeed(final long long1) {
        final int integer3 = 1024;
        if (long1 < 1024L) {
            return long1 + " B/s";
        }
        final int integer4 = (int)(Math.log((double)long1) / Math.log(1024.0));
        final String string5 = "KMGTPE".charAt(integer4 - 1) + "";
        return String.format(Locale.ROOT, "%.1f %sB/s", long1 / Math.pow(1024.0, integer4), string5);
    }
    
    public static String humanReadableSize(final long long1) {
        final int integer3 = 1024;
        if (long1 < 1024L) {
            return long1 + " B";
        }
        final int integer4 = (int)(Math.log((double)long1) / Math.log(1024.0));
        final String string5 = "KMGTPE".charAt(integer4 - 1) + "";
        return String.format(Locale.ROOT, "%.0f %sB", long1 / Math.pow(1024.0, integer4), string5);
    }
    
    private void downloadSave() {
        FileDownload cyv2;
        new Thread(() -> {
            try {
                if (!(!RealmsDownloadLatestWorldScreen.downloadLock.tryLock(1L, TimeUnit.SECONDS))) {
                    this.status = RealmsScreen.getLocalizedString("mco.download.preparing");
                    if (this.cancelled) {
                        this.downloadCancelled();
                    }
                    else {
                        this.status = RealmsScreen.getLocalizedString("mco.download.downloading", this.worldName);
                        cyv2 = new FileDownload();
                        cyv2.contentLength(this.worldDownload.downloadLink);
                        cyv2.download(this.worldDownload, this.worldName, this.downloadStatus, this.getLevelStorageSource());
                        while (!cyv2.isFinished()) {
                            if (cyv2.isError()) {
                                cyv2.cancel();
                                this.errorMessage = RealmsScreen.getLocalizedString("mco.download.failed");
                                this.cancelButton.setMessage(RealmsScreen.getLocalizedString("gui.done"));
                                return;
                            }
                            else {
                                if (cyv2.isExtracting()) {
                                    this.extracting = true;
                                }
                                if (this.cancelled) {
                                    cyv2.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 = RealmsScreen.getLocalizedString("mco.download.done");
                        this.cancelButton.setMessage(RealmsScreen.getLocalizedString("gui.done"));
                    }
                }
            }
            catch (InterruptedException interruptedException4) {
                RealmsDownloadLatestWorldScreen.LOGGER.error("Could not acquire upload lock");
            }
            catch (Exception exception2) {
                this.errorMessage = RealmsScreen.getLocalizedString("mco.download.failed");
                exception2.printStackTrace();
            }
            finally {
                if (RealmsDownloadLatestWorldScreen.downloadLock.isHeldByCurrentThread()) {
                    RealmsDownloadLatestWorldScreen.downloadLock.unlock();
                    this.showDots = false;
                    this.finished = true;
                }
            }
        }).start();
    }
    
    private void downloadCancelled() {
        this.status = RealmsScreen.getLocalizedString("mco.download.cancelled");
    }
    
    static {
        LOGGER = LogManager.getLogger();
        DOTS = new String[] { "", ".", ". .", ". . ." };
        downloadLock = new ReentrantLock();
    }
    
    public class DownloadStatus {
        public volatile Long bytesWritten;
        public volatile Long totalBytes;
        
        public DownloadStatus() {
            this.bytesWritten = 0L;
            this.totalBytes = 0L;
        }
    }
}
