/*
 *   This file is a part of the SteamWar software.
 *
 *   Copyright (C) 2025 SteamWar.de-Serverteam
 *
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU Affero General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *   GNU Affero General Public License for more details.
 *
 *   You should have received a copy of the GNU Affero General Public License
 *   along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

package de.steamwar.network.packets;

import lombok.SneakyThrows;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public abstract class PacketHandler {

    private static final List<PacketHandler> PACKET_HANDLERS = new ArrayList<>();

    private final Map<Class<? extends NetworkPacket>, Method> HANDLER_MAP = new HashMap<>();

    public static void handlePacket(NetworkPacket packet) {
        for (PacketHandler handler : PACKET_HANDLERS) {
            handler.handle(packet);
        }
    }

    protected PacketHandler() {
        Method[] methods = getClass().getMethods();
        for (Method method : methods) {
            if (method.getParameterCount() != 1 || !NetworkPacket.class.isAssignableFrom(method.getParameterTypes()[0])) {
                continue;
            }

            if (method.isAnnotationPresent(Handler.class)) {
                Class<? extends NetworkPacket> packetClass = (Class<? extends NetworkPacket>) method.getParameterTypes()[0];
                HANDLER_MAP.put(packetClass, method);
            }
        }
    }

    public void register() {
        PACKET_HANDLERS.add(this);
    }

    public void unregister() {
        PACKET_HANDLERS.remove(this);
    }

    @SneakyThrows
    public void handle(NetworkPacket packet) {
        Method method = HANDLER_MAP.get(packet.getClass());
        if (method == null) {
            return;
        }
        method.invoke(this, packet);
    }

    @Retention(RetentionPolicy.RUNTIME)
    protected @interface Handler {
    }
}
