package net.minecraft.server.level;

import net.minecraft.core.Registry;
import net.minecraft.core.registries.BuiltInRegistries;

public final class TicketType<T> implements ca.spottedleaf.moonrise.patches.chunk_system.ticket.ChunkSystemTicketType<T> { // Paper - rewrite chunk system
    // Paper start - rewrite chunk system
    private static final java.util.concurrent.atomic.AtomicLong ID_GENERATOR = new java.util.concurrent.atomic.AtomicLong();
    private final long id = ID_GENERATOR.getAndIncrement();
    private java.util.Comparator<T> identifierComparator;
    private volatile long[] counterTypes;

    @Override
    public final long moonrise$getId() {
        return this.id;
    }

    @Override
    public final java.util.Comparator<T> moonrise$getIdentifierComparator() {
        return this.identifierComparator;
    }

    @Override
    public final void moonrise$setIdentifierComparator(final java.util.Comparator<T> comparator) {
        this.identifierComparator = comparator;
    }

    @Override
    public final long[] moonrise$getCounterTypes() {
        // need to lazy init this because we cannot check if we are FORCED during construction
        final long[] types = this.counterTypes;
        if (types != null) {
            return types;
        }

        return this.counterTypes = ca.spottedleaf.moonrise.common.PlatformHooks.get().getCounterTypesUncached((TicketType)(Object)this);
    }

    @Override
    public final void moonrise$setTimeout(final long to) {
        this.timeout = to;
    }
    // Paper end - rewrite chunk system

    public static final long NO_TIMEOUT = 0L;
    public static final TicketType START = register("start", 0L, false, TicketType.TicketUse.LOADING_AND_SIMULATION);
    public static final TicketType DRAGON = register("dragon", 0L, false, TicketType.TicketUse.LOADING_AND_SIMULATION);
    public static final TicketType PLAYER_LOADING = register("player_loading", 0L, false, TicketType.TicketUse.LOADING);
    public static final TicketType PLAYER_SIMULATION = register("player_simulation", 0L, false, TicketType.TicketUse.SIMULATION);
    public static final TicketType FORCED = register("forced", 0L, true, TicketType.TicketUse.LOADING_AND_SIMULATION);
    public static final TicketType PORTAL = register("portal", 300L, me.earthme.luminol.config.modules.misc.SavePortalTicketsConfig.doSave, TicketType.TicketUse.LOADING_AND_SIMULATION); // Luminol - Add config for whether to save portal tickets
    public static final TicketType ENDER_PEARL = register("ender_pearl", 40L, false, TicketType.TicketUse.LOADING_AND_SIMULATION);
    public static final TicketType UNKNOWN = register("unknown", 5L, false, TicketType.TicketUse.LOADING); // Folia - region threading
    public static final TicketType PLUGIN = register("plugin", 0L, false, TicketType.TicketUse.LOADING_AND_SIMULATION); // CraftBukkit
    public static final TicketType POST_TELEPORT = register("post_teleport", 5L, false, TicketType.TicketUse.LOADING_AND_SIMULATION); // Paper
    public static final TicketType PLUGIN_TICKET = register("plugin_ticket", TicketType.NO_TIMEOUT, false, TicketType.TicketUse.LOADING_AND_SIMULATION); static { ((TicketType<org.bukkit.plugin.Plugin>)PLUGIN_TICKET).moonrise$setIdentifierComparator((org.bukkit.plugin.Plugin p1, org.bukkit.plugin.Plugin p2) -> p1.getName().compareTo(p2.getName())); } // Paper // Paper - rewrite chunk system
    public static final TicketType FUTURE_AWAIT = register("future_await", TicketType.NO_TIMEOUT, false, TicketType.TicketUse.LOADING_AND_SIMULATION); // Paper
    public static final TicketType CHUNK_LOAD = register("chunk_load", TicketType.NO_TIMEOUT, false, TicketType.TicketUse.LOADING); // Paper - moonrise
    // Folia start - region threading
    public static final TicketType LOGIN = register("folia:login", 20L, false, TicketType.TicketUse.LOADING_AND_SIMULATION);
    public static final TicketType DELAYED = register("folia:delay", 5L, false, TicketType.TicketUse.LOADING_AND_SIMULATION);
    public static final TicketType<Long> END_GATEWAY_EXIT_SEARCH = ca.spottedleaf.moonrise.patches.chunk_system.ticket.ChunkSystemTicketType.create("folia:end_gateway_exit_search", Long::compareTo);
    public static final TicketType<Long> NETHER_PORTAL_DOUBLE_CHECK = ca.spottedleaf.moonrise.patches.chunk_system.ticket.ChunkSystemTicketType.create("folia:nether_portal_double_check", Long::compareTo);
    public static final TicketType<Long> TELEPORT_HOLD_TICKET = ca.spottedleaf.moonrise.patches.chunk_system.ticket.ChunkSystemTicketType.create("folia:teleport_hold_ticket", Long::compareTo);
    public static final TicketType REGION_SCHEDULER_API_HOLD = register("folia:region_scheduler_api_hold", 0L, false, TicketType.TicketUse.LOADING_AND_SIMULATION);
    // Folia end - region threading

    public static TicketType register(String name, long timeout, boolean persist, TicketType.TicketUse use) {
        return Registry.register(BuiltInRegistries.TICKET_TYPE, name, new TicketType(timeout, persist, use));
    }

    // Paper start - rewrite chunk system - convert to class
    private long timeout; // Paper - rewrite chunk system - remove final
    private final boolean persist;
    private final net.minecraft.server.level.TicketType.TicketUse use;

    public TicketType(long timeout, boolean persist, net.minecraft.server.level.TicketType.TicketUse use) {
        this.timeout = timeout;
        this.persist = persist;
        this.use = use;
    }

    public boolean persist() {
        return this.persist;
    }

    public net.minecraft.server.level.TicketType.TicketUse use() {
        return this.use;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == this) return true;
        if (obj == null || obj.getClass() != this.getClass()) return false;
        var that = (net.minecraft.server.level.TicketType) obj;
        return this.timeout == that.timeout &&
            this.persist == that.persist &&
            java.util.Objects.equals(this.use, that.use);
    }

    @Override
    public int hashCode() {
        return java.util.Objects.hash(timeout, persist, use);
    }

    @Override
    public String toString() {
        return "TicketType[" +
            "timeout=" + timeout + ", " +
            "persist=" + persist + ", " +
            "use=" + use + ']';
    }
    // Paper end - rewrite chunk system - convert to class

    // Paper start - chunk-gc config
    public static int PLUGIN_TYPE_TIMEOUT = 600;
    // Paper - rewrite chunk system - convert to class
    public long timeout() {
        return this == PLUGIN ? PLUGIN_TYPE_TIMEOUT : this.timeout;
    }
    // Paper end - chunk-gc config

    public boolean doesLoad() {
        return this.use == TicketType.TicketUse.LOADING || this.use == TicketType.TicketUse.LOADING_AND_SIMULATION;
    }

    public boolean doesSimulate() {
        return this.use == TicketType.TicketUse.SIMULATION || this.use == TicketType.TicketUse.LOADING_AND_SIMULATION;
    }

    public boolean hasTimeout() {
        return this.timeout() != 0L; // Paper - chunk-gc config
    }

    public static enum TicketUse {
        LOADING,
        SIMULATION,
        LOADING_AND_SIMULATION;
    }
}
