/*
 *  Copyright 2025-2026 R3944Realms
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package top.r3944realms.eroticdungeongame.core.network.toServer;

import net.minecraft.ChatFormatting;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.network.FilteredText;
import net.minecraft.server.network.TextFilter;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.network.NetworkEvent;
import org.jetbrains.annotations.NotNull;
import top.r3944realms.eroticdungeongame.EroticDungeon;
import top.r3944realms.eroticdungeongame.content.item.SignArmorItem;

import java.util.List;
import java.util.UUID;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletableFuture;
import java.util.function.BiFunction;
import java.util.function.Supplier;
import java.util.stream.Stream;

public record SignArmorUpdatePacket(UUID entityUUID, boolean isEditInHand, String line1, String line2, String line3, String line4) {
    private static final int MAX_STRING_LENGTH = 384;

    public SignArmorUpdatePacket(@NotNull FriendlyByteBuf buf) {
        this(buf.readUUID(), buf.readBoolean(),  buf.readUtf(MAX_STRING_LENGTH), buf.readUtf(MAX_STRING_LENGTH), buf.readUtf(MAX_STRING_LENGTH), buf.readUtf(MAX_STRING_LENGTH));
    }

    public void encode(@NotNull FriendlyByteBuf buf) {
        buf.writeUUID(entityUUID);
        buf.writeBoolean(isEditInHand);
        buf.writeUtf(line1);
        buf.writeUtf(line2);
        buf.writeUtf(line3);
        buf.writeUtf(line4);
    }

    public void handle(@NotNull Supplier<NetworkEvent.Context> contextSupplier) {
        NetworkEvent.Context context = contextSupplier.get();
        context.enqueueWork(() -> {
            List<String> list = Stream.of(line1, line2, line3, line4).map(ChatFormatting::stripFormatting).toList();
            ServerPlayer sender = context.getSender();
            if (sender != null) {
                filterTextPacket(
                        sender, list
               ).thenAcceptAsync(
                       filteredText -> this.updateSignText(sender, filteredText)
                );
            }
        });
        context.setPacketHandled(true);
    }
    private void updateSignText(@NotNull ServerPlayer sender, List<FilteredText> filteredText) {
        sender.resetLastActionTime();
        ServerLevel serverlevel = sender.serverLevel();
        if (isEditInHand) {
            if (sender.getUUID().equals(entityUUID)) {
                ItemStack mainHand = sender.getItemInHand(InteractionHand.MAIN_HAND);
                ItemStack offHand = sender.getItemInHand(InteractionHand.OFF_HAND);
                if (mainHand.getItem() instanceof SignArmorItem signArmorItem) {
                    signArmorItem.updateSignText(mainHand, sender, filteredText);
                } else if (offHand.getItem() instanceof SignArmorItem signArmorItem) {
                    signArmorItem.updateSignText(offHand, sender, filteredText);
                } else EroticDungeon.LOGGER.warn("Can't find vaild armor item from sender {}", sender.getUUID());
            } else EroticDungeon.LOGGER.warn("Entity {} which is not sender {} is editing in in-hand packet", entityUUID, sender.getUUID());
        } else {
            Entity entity = serverlevel.getEntity(entityUUID);
            if (entity instanceof LivingEntity living) {
                ItemStack itemStack = living.getItemBySlot(EquipmentSlot.CHEST);
                if (!itemStack.isEmpty() && itemStack.getItem() instanceof SignArmorItem signArmorItem) {
                    signArmorItem.updateSignText(itemStack, sender, filteredText);
                }
            }
        }

    }

    private <T, R> CompletableFuture<R> filterTextPacket(@NotNull ServerPlayer sender, T message, @NotNull BiFunction<TextFilter, T, CompletableFuture<R>> processor) {
        return processor.apply(sender.getTextFilter(), message).thenApply((message1) -> {
            if (!sender.connection.isAcceptingMessages()) {
                EroticDungeon.LOGGER.debug("Ignoring packet due to disconnection");
                throw new CancellationException("disconnected");
            } else {
                return message1;
            }
        });
    }
    private CompletableFuture<FilteredText> filterTextPacket(ServerPlayer sender,String text) {
        return this.filterTextPacket(sender, text, TextFilter::processStreamMessage);
    }

    private CompletableFuture<List<FilteredText>> filterTextPacket(ServerPlayer sender,List<String> texts) {
        return this.filterTextPacket(sender, texts, TextFilter::processMessageBundle);
    }
}
