package net.puzzlemc.splashscreen;

import com.mojang.blaze3d.pipeline.BlendFunction;
import com.mojang.blaze3d.pipeline.RenderPipeline;
import com.mojang.blaze3d.platform.DepthTestFunction;
import com.mojang.blaze3d.platform.DestFactor;
import com.mojang.blaze3d.platform.NativeImage;
import com.mojang.blaze3d.platform.SourceFactor;
import eu.midnightdust.lib.util.MidnightColorUtil;
import eu.midnightdust.lib.util.PlatformFunctions;
import net.minecraft.Util;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.texture.DynamicTexture;
import net.minecraft.client.renderer.texture.ReloadableTexture;
import net.minecraft.client.renderer.texture.TextureContents;
import net.minecraft.client.resources.metadata.texture.TextureMetadataSection;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.PackType;
import net.minecraft.server.packs.VanillaPackResources;
import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraft.server.packs.resources.ResourceManagerReloadListener;
import net.puzzlemc.core.config.PuzzleConfig;
import net.puzzlemc.splashscreen.mixin.RenderPipelinesAccessor;
import org.jetbrains.annotations.NotNull;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;

import static net.puzzlemc.core.PuzzleCore.LOGGER;
import static net.puzzlemc.core.PuzzleCore.MOD_ID;

public class PuzzleSplashScreen {
    public static final ResourceLocation LOGO = ResourceLocation.withDefaultNamespace("textures/gui/title/mojangstudios.png");
    public static final ResourceLocation BACKGROUND = ResourceLocation.withDefaultNamespace("puzzle/splash_background.png");
    public static File CONFIG_PATH = new File(String.valueOf(PlatformFunctions.getConfigDirectory().resolve(".puzzle_cache")));
    public static Path LOGO_TEXTURE = Paths.get(CONFIG_PATH + "/mojangstudios.png");
    public static Path BACKGROUND_TEXTURE = Paths.get(CONFIG_PATH + "/splash_background.png");
    private static Minecraft client = Minecraft.getInstance();
    private static boolean keepBackground = false;
    private static RenderPipeline CUSTOM_LOGO_PIPELINE;

    public static void init() {
        if (!CONFIG_PATH.exists()) { // Run when config directory is nonexistent //
            if (CONFIG_PATH.mkdir()) { // Create our custom config directory //
                if (Util.getPlatform().equals(Util.OS.WINDOWS)) {
                    try { Files.setAttribute(CONFIG_PATH.toPath(), "dos:hidden", true);
                    } catch (IOException ignored) {}
                }
            }
        }
        buildRenderLayer();
    }

    public static RenderPipeline getCustomLogoRenderPipeline() {
        return CUSTOM_LOGO_PIPELINE;
    }

    public static void buildRenderLayer() {
        if (PuzzleConfig.resourcepackSplashScreen) {
            BlendFunction blendFunction = new BlendFunction(SourceFactor.SRC_ALPHA, DestFactor.ONE);
            if (PuzzleConfig.disableBlend) blendFunction = null;
            else if (PuzzleConfig.customBlendFunction.size() == 4) {
                try {
                    blendFunction = new BlendFunction(
                            SourceFactor.valueOf(PuzzleConfig.customBlendFunction.get(0)),
                            DestFactor.valueOf(PuzzleConfig.customBlendFunction.get(1)),
                            SourceFactor.valueOf(PuzzleConfig.customBlendFunction.get(2)),
                            DestFactor.valueOf(PuzzleConfig.customBlendFunction.get(3)));
                } catch (Exception e) {
                    LOGGER.error("Incorrect blend function defined in color.properties: {}{}", PuzzleConfig.customBlendFunction, e.getMessage());
                }
            }

            var CUSTOM_LOGO_PIPELINE_BUILDER = RenderPipeline.builder(RenderPipelinesAccessor.getGUI_TEXTURED_SNIPPET())
                .withLocation("pipeline/mojang_logo_puzzle")
                .withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST)
                .withDepthWrite(false);
            CUSTOM_LOGO_PIPELINE_BUILDER = blendFunction != null ? CUSTOM_LOGO_PIPELINE_BUILDER.withBlend(blendFunction) : CUSTOM_LOGO_PIPELINE_BUILDER.withoutBlend();

            CUSTOM_LOGO_PIPELINE = CUSTOM_LOGO_PIPELINE_BUILDER.build();
        }
    }

    public static class ReloadListener implements ResourceManagerReloadListener {
        public static final ReloadListener INSTANCE = new ReloadListener();

        private ReloadListener() {}

        @Override
        public void onResourceManagerReload(ResourceManager manager) {
            client = Minecraft.getInstance();
            if (PuzzleConfig.resourcepackSplashScreen) {
                PuzzleSplashScreen.resetColors();
                client.getTextureManager().registerAndLoad(LOGO, new LogoTexture(LOGO));
                client.getTextureManager().registerAndLoad(BACKGROUND, new LogoTexture(BACKGROUND));

                manager.listResources("optifine", path -> path.getPath().contains("color.properties")).forEach((id, resource) -> {
                    try (InputStream stream = resource.open()) {
                        Properties properties = new Properties();
                        properties.load(stream);

                        if (properties.get("screen.loading") != null) {
                            PuzzleConfig.backgroundColor = MidnightColorUtil.hex2Rgb(properties.get("screen.loading").toString()).getRGB();
                            PuzzleConfig.hasCustomSplashScreen = true;
                        }
                        if (properties.get("screen.loading.bar") != null) {
                            PuzzleConfig.progressBarBackgroundColor = MidnightColorUtil.hex2Rgb(properties.get("screen.loading.bar").toString()).getRGB();
                            PuzzleConfig.hasCustomSplashScreen = true;
                        }
                        if (properties.get("screen.loading.progress") != null) {
                            PuzzleConfig.progressBarColor = MidnightColorUtil.hex2Rgb(properties.get("screen.loading.progress").toString()).getRGB();
                            PuzzleConfig.hasCustomSplashScreen = true;
                        }
                        if (properties.get("screen.loading.outline") != null) {
                            PuzzleConfig.progressFrameColor = MidnightColorUtil.hex2Rgb(properties.get("screen.loading.outline").toString()).getRGB();
                            PuzzleConfig.hasCustomSplashScreen = true;
                        }
                        if (properties.get("screen.loading.blend") != null) {
                            // Recommended blend: SRC_ALPHA ONE_MINUS_SRC_ALPHA ONE ZERO
                            PuzzleConfig.disableBlend = properties.get("screen.loading.blend").toString().equals("off");
                            PuzzleConfig.customBlendFunction = new ArrayList<>(Arrays.stream(properties.get("screen.loading.blend").toString().split(" ")).toList());
                            PuzzleConfig.hasCustomSplashScreen = true;
                        }

                    } catch (Exception e) {
                        LOGGER.error("Error occurred while loading color.properties {}", id.toString(), e);
                    }
                });
                AtomicInteger logoCount = new AtomicInteger();
                manager.listResources("textures", path -> path.getPath().contains("mojangstudios.png")).forEach((id, resource) -> {
                    try (InputStream stream = resource.open()) {
                        Files.copy(stream, LOGO_TEXTURE, StandardCopyOption.REPLACE_EXISTING);
                        client.getTextureManager().registerAndLoad(LOGO, new DynamicLogoTexture());
                        if (logoCount.get() > 0) PuzzleConfig.hasCustomSplashScreen = true;
                        logoCount.getAndIncrement();
                    } catch (Exception e) {
                        LOGGER.error("Error occurred while loading custom minecraft logo {}", id.toString(), e);
                    }
                });
                manager.listResources(MOD_ID, path -> path.getPath().contains("splash_background.png")).forEach((id, resource) -> {
                    try (InputStream stream = resource.open()) {
                        Files.copy(stream, BACKGROUND_TEXTURE, StandardCopyOption.REPLACE_EXISTING);
                        InputStream input = new FileInputStream(String.valueOf(PuzzleSplashScreen.BACKGROUND_TEXTURE));
                        client.getTextureManager().register(BACKGROUND, new DynamicTexture(() -> "splash_screen_background", NativeImage.read(input)));
                        keepBackground = true;
                        PuzzleConfig.hasCustomSplashScreen = true;
                    } catch (Exception e) {
                        LOGGER.error("Error occurred while loading custom splash background {}", id.toString(), e);
                    }
                });
                if (!keepBackground) {
                    try {
                        Files.delete(BACKGROUND_TEXTURE);
                    } catch (Exception ignored) {}
                }
                keepBackground = false;
                PuzzleConfig.write(MOD_ID);
                buildRenderLayer();
            }
        }
    }

    public static void resetColors() {
        PuzzleConfig.backgroundColor = 15675965;
        PuzzleConfig.progressBarColor = 16777215;
        PuzzleConfig.progressBarBackgroundColor = 15675965;
        PuzzleConfig.progressFrameColor = 16777215;
        PuzzleConfig.disableBlend = false;
        PuzzleConfig.customBlendFunction = new ArrayList<>();
        PuzzleConfig.hasCustomSplashScreen = false;
    }

    public static class LogoTexture extends ReloadableTexture {
        public LogoTexture(ResourceLocation logo) { super(logo); }

        @Override
        public @NotNull TextureContents loadContents(ResourceManager resourceManager) {
            Minecraft client = Minecraft.getInstance();
            VanillaPackResources defaultResourcePack = client.getVanillaPackResources();
            try {
                InputStream inputStream = Objects.requireNonNull(defaultResourcePack.getResource(PackType.CLIENT_RESOURCES, LOGO)).get();
                TextureContents tex;
                try {
                    tex = new TextureContents(NativeImage.read(inputStream), new TextureMetadataSection(true, true));
                } finally {
                    inputStream.close();
                }
                return tex;
            } catch (IOException var18) {
                return TextureContents.createMissing();
            }
        }
    }

    public static class DynamicLogoTexture extends ReloadableTexture {
        public DynamicLogoTexture() {
            super(LOGO);
        }
        @Override
        public @NotNull TextureContents loadContents(ResourceManager resourceManager) {
            try {
                InputStream input = new FileInputStream(String.valueOf(PuzzleSplashScreen.LOGO_TEXTURE));
                return new TextureContents(NativeImage.read(input), new TextureMetadataSection(true, true));
            } catch (IOException e) {
                LOGGER.error("Encountered an error during logo loading: ", e);
                try {
                    return TextureContents.load(resourceManager, LOGO);
                } catch (IOException ex) {
                    return TextureContents.createMissing();
                }
            }
        }
    }
}
