/*
 *  Super Lead rope mod
 *  Copyright (C)  2025  R3944Realms
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU 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 阿 PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

package top.r3944realms.superleadrope.client.renderer;

import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.Level;
import top.r3944realms.superleadrope.SuperLeadRope;
import top.r3944realms.superleadrope.api.type.capabilty.LeashInfo;
import top.r3944realms.superleadrope.client.renderer.resolver.SuperLeashStateResolver;
import top.r3944realms.superleadrope.content.entity.SuperLeashKnotEntity;
import top.r3944realms.superleadrope.util.capability.LeashDataInnerAPI;

import java.util.Optional;
import java.util.UUID;

/**
 * The type Leash render handler.
 */
public class LeashRenderHandler {
    /**
     * On render level stage.
     *
     * @param poseStack   the pose stack
     * @param partialTick the partial tick
     */
    public static void onRenderLevelStage(PoseStack poseStack, float partialTick) {
        renderAllCustomLeashes(poseStack, partialTick);
    }

    private static void renderAllCustomLeashes(PoseStack poseStack, float partialTick) {
        Minecraft minecraft = Minecraft.getInstance();
        Level level = minecraft.level;
        Entity cameraEntity = minecraft.getCameraEntity();
        if (level == null || cameraEntity == null) return;

        MultiBufferSource.BufferSource bufferSource = minecraft.renderBuffers().bufferSource();

        // 遍历摄像机附近所有实体
        for (Entity entity : level.getEntitiesOfClass(Entity.class,
                cameraEntity.getBoundingBox().inflate(32*16))) {

            LeashDataInnerAPI.getLeashData(entity).ifPresent(leashData -> {
                for (LeashInfo leashInfo : leashData.getAllLeashes()) {
                    renderLeashFromInfo(entity, leashInfo, poseStack, bufferSource, partialTick);
                }
            });
        }
    }

    private static void renderLeashFromInfo(Entity entity, LeashInfo leashInfo,
                                            PoseStack poseStack, MultiBufferSource bufferSource,
                                            float partialTick) {
        try {
            Optional<Entity> holderOpt = getHolderFromLeashInfo(entity.level(), leashInfo);
            if (holderOpt.isEmpty()) return;

            Entity holder = holderOpt.get();

            // 构建渲染状态
            SuperLeashStateResolver.resolve(holder, entity, leashInfo, partialTick).ifPresent(
                    leashRenderState -> SuperLeashRenderer.renderLeash(leashRenderState, poseStack, bufferSource)
            );


        } catch (Exception e) {
            SuperLeadRope.logger.error("Failed to render leash", e);
        }
    }

    private static Optional<Entity> getHolderFromLeashInfo(Level level, LeashInfo leashInfo) {
        if (leashInfo.blockPosOpt().isPresent()) {
            BlockPos pos = leashInfo.blockPosOpt().get();
            return SuperLeashKnotEntity.get(level,pos).map(Entity.class::cast);
        } else if (leashInfo.holderUUIDOpt().isPresent()) {
            UUID holderUUID = leashInfo.holderUUIDOpt().get();
            for (Entity e : ((ClientLevel)level).entitiesForRendering()) {
                if (e.getUUID().equals(holderUUID)) return Optional.of(e);
            }
        }
        return Optional.empty();
    }
}