package dev.photosync.platform.impl;

import dev.photosync.core.capture.CameraPose;
import dev.photosync.mcapi.GameContext;
import dev.photosync.platform.UserDataDirectory;
import dev.photosync.platform.WindowTitle;
import lombok.extern.slf4j.Slf4j;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.util.Util;
import net.minecraft.client.Minecraft;
import net.minecraft.world.entity.Entity;

import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Optional;

/** Ambient client state, the render thread, and the way out of the game. */
@Slf4j
public final class GameAdapter implements GameContext {

    /**
     * Both resolved from the loader rather than from Minecraft, because this is
     * built while Minecraft is still constructing itself -- and because the
     * loader's answers have not moved once in the supported range.
     */
    private final Path configDirectory = FabricLoader.getInstance().getConfigDir().resolve("photosync");
    private final Path userDataDirectory = UserDataDirectory.resolve();
    private final String minecraftVersion = FabricLoader.getInstance()
            .getModContainer("minecraft")
            .map(container -> container.getMetadata().getVersion().getFriendlyString())
            .orElse("unknown");

    @Override
    public boolean inWorld() {
        return Minecraft.getInstance().level != null;
    }

    /** 26.1 moved the current screen from {@code Minecraft} onto {@code Gui}. */
    @Override
    public boolean screenOpen() {
        return Minecraft.getInstance().gui.screen() != null;
    }

    /**
     * The camera entity rather than the player, so that a spectator following
     * someone else is judged on what the screenshot will actually show. It falls
     * back to the player, and is null until one exists.
     */
    @Override
    public Optional<CameraPose> cameraPose() {
        Entity camera = Minecraft.getInstance().getCameraEntity();
        return camera == null
                ? Optional.empty()
                : Optional.of(new CameraPose(camera.getX(), camera.getY(), camera.getZ(),
                        camera.getYRot(), camera.getXRot()));
    }

    @Override
    public Path configDirectory() {
        return configDirectory;
    }

    @Override
    public Path userDataDirectory() {
        return userDataDirectory;
    }

    @Override
    public void submit(Runnable task) {
        Minecraft game = Minecraft.getInstance();
        if (game.isSameThread()) {
            task.run();
        } else {
            game.execute(task);
        }
    }

    /**
     * Opens the containing folder, not the file.
     *
     * <p>There is no cross-platform "reveal and select", and handing a PNG to
     * the desktop opens an image viewer -- which the player already has, since
     * they are looking at the screenshot in the queue screen. What they cannot
     * get to is the folder.
     */
    @Override
    public void reveal(Path path) {
        Path target = Files.isDirectory(path) ? path : path.getParent();
        if (target == null) {
            return;
        }
        Util.getPlatform().openFile(target.toFile());
    }

    @Override
    public String minecraftVersion() {
        return minecraftVersion;
    }

    @Override
    public String clientName() {
        String title = WindowTitle.last();
        return title == null || title.isBlank() ? "Minecraft" : title;
    }

    @Override
    public Optional<String> serverAddress() {
        return Optional.ofNullable(Minecraft.getInstance().getCurrentServer())
                .map(server -> server.ip);
    }

    @Override
    public void quit() {
        Minecraft.getInstance().stop();
    }
}
