/*
 *  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.client.gui.screens;

import com.mojang.blaze3d.platform.Lighting;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.font.TextFieldHelper;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.network.chat.CommonComponents;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.entity.SignText;
import net.minecraft.world.level.block.state.properties.WoodType;
import org.jetbrains.annotations.NotNull;
import org.joml.Vector3f;
import top.r3944realms.eroticdungeongame.EroticDungeon;
import top.r3944realms.eroticdungeongame.content.item.SignArmorItem;
import top.r3944realms.eroticdungeongame.core.network.EDGNetworkHandler;
import top.r3944realms.eroticdungeongame.core.network.toServer.SignArmorUpdatePacket;

import javax.annotation.Nullable;
import java.util.stream.IntStream;

public class SignArmorEditScreen extends Screen {
    private final LivingEntity holder;
    private static final Vector3f TEXT_SCALE = new Vector3f(1.0F, 1.0F, 1.0F);
    private static final int TEXTURE_WIDTH = 16;
    private static final int TEXTURE_HEIGHT = 16;
    private final ResourceLocation texture;
    private SignText text;
    private final String[] messages;
    protected final WoodType woodType;
    private int frame;
    private int line;
    @Nullable
    private TextFieldHelper signField;
    @NotNull
    private final SignArmorItem item;
    private final ItemStack itemStack;

    private final boolean isEditInHand;
    public SignArmorEditScreen(@NotNull LivingEntity holder, boolean isEditInHand, boolean isFiltered) {
        this(holder, isEditInHand, findSignArmorItemStack(holder, isEditInHand), isFiltered, Component.translatable("sign.edit"));
    }
    private static @NotNull ItemStack findSignArmorItemStack(LivingEntity holder, boolean isEditInHand) {
        if (isEditInHand) {
            ItemStack main = holder.getItemBySlot(EquipmentSlot.MAINHAND);
            ItemStack off = holder.getItemBySlot(EquipmentSlot.OFFHAND);
            if (main.getItem() instanceof SignArmorItem) {
                return main;
            } else if (off.getItem() instanceof SignArmorItem) {
                return off;
            }
            throw new IllegalStateException("Can't find sign armor item for holder: " + holder);
        } else {
            ItemStack itemBySlot = holder.getItemBySlot(EquipmentSlot.CHEST);
            if (itemBySlot.getItem() instanceof SignArmorItem) {
                return itemBySlot;
            } else throw new IllegalArgumentException("Excepted for SignArmorItem but found " + itemBySlot.getItem().getClass().getSimpleName());
        }
    }

    public SignArmorEditScreen(LivingEntity holder, boolean isEditInHand, @NotNull ItemStack signArmorItemStack, boolean isFiltered, Component title) {
        super(title);
        this.holder = holder;
        this.isEditInHand = isEditInHand;
        if (signArmorItemStack.getItem() instanceof SignArmorItem signArmorItem) {
            item = signArmorItem;

        } else {
            throw new IllegalArgumentException("Excepted for SignArmorItem but found " + signArmorItemStack.getClass().getSimpleName());
        }
        itemStack = signArmorItemStack;
        this.text = item.getSignText(signArmorItemStack);
        this.woodType = item.getWoodType();
        this.texture = EroticDungeon.mrl(this.woodType.name() + ".png").withPrefix("textures/gui/hanging_signs/");
        this.messages = IntStream.range(0, 4).mapToObj((message) -> this.text.getMessage(message, isFiltered)).map(Component::getString).toArray(String[]::new);
    }

    @Override
    protected void init() {
        this.addRenderableWidget(Button.builder(CommonComponents.GUI_DONE, (p_251194_) -> {
            this.onDone();
        }).bounds(this.width / 2 - 100, this.height / 4 + 144, 200, 20).build());
        assert this.minecraft != null;
        this.signField = new TextFieldHelper(() -> this.messages[this.line], this::setMessage, TextFieldHelper.createClipboardGetter(this.minecraft), TextFieldHelper.createClipboardSetter(this.minecraft), (p_280850_) -> this.minecraft.font.width(p_280850_) <= this.item.getMaxTextLineWidth());
    }

    @Override
    public void tick() {
        ++this.frame;
        if (!this.isValid()) {
            this.onDone();
        }

    }

    private boolean isValid() {
        return this.minecraft != null && this.minecraft.player != null;
    }

    @Override
    public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
        if (keyCode == 265) {
            this.line = this.line - 1 & 3;
            assert this.signField != null;
            this.signField.setCursorToEnd();
            return true;
        } else if (keyCode != 264 && keyCode != 257 && keyCode != 335) {
            assert this.signField != null;
            return this.signField.keyPressed(keyCode) || super.keyPressed(keyCode, scanCode, modifiers);
        } else {
            this.line = this.line + 1 & 3;
            assert this.signField != null;
            this.signField.setCursorToEnd();
            return true;
        }
    }

    @Override
    public boolean charTyped(char codePoint, int modifiers) {
        assert this.signField != null;
        this.signField.charTyped(codePoint);
        return true;
    }

    public void render(@NotNull GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) {
        Lighting.setupForFlatItems();
        this.renderBackground(guiGraphics);
        guiGraphics.drawCenteredString(this.font, this.title, this.width / 2, 40, 16777215);
        this.renderSign(guiGraphics);
        Lighting.setupFor3DItems();
        super.render(guiGraphics, mouseX, mouseY, partialTick);
    }

    @Override
    public void onClose() {
        this.onDone();
    }

    @Override
    public void removed() {
        assert this.minecraft != null;
        EDGNetworkHandler.sendToServer(new SignArmorUpdatePacket(holder.getUUID(), isEditInHand, messages[0], messages[1], messages[2], messages[3]));

    }

    @Override
    public boolean isPauseScreen() {
        return false;
    }

    protected void renderSignBackground(@NotNull GuiGraphics graphics) {
        graphics.pose().translate(0.0F, -13.0F, 0.0F);
        graphics.pose().scale(4.5F, 4.5F, 1.0F);
        graphics.blit(this.texture, -8, -8, 0.0F, 0.0F, TEXTURE_WIDTH, TEXTURE_HEIGHT, TEXTURE_WIDTH, TEXTURE_HEIGHT);
    }

    protected Vector3f getSignTextScale() {
        return TEXT_SCALE;
    }

    protected void offsetSign(@NotNull GuiGraphics guiGraphics) {
        guiGraphics.pose().translate((float)this.width / 2.0F, 125.0F, 50.0F);
    }

    private void renderSign(@NotNull GuiGraphics guiGraphics) {
        guiGraphics.pose().pushPose();
        this.offsetSign(guiGraphics);
        guiGraphics.pose().pushPose();
        this.renderSignBackground(guiGraphics);
        guiGraphics.pose().popPose();
        this.renderSignText(guiGraphics);
        guiGraphics.pose().popPose();
    }

    private void renderSignText(@NotNull GuiGraphics guiGraphics) {
        guiGraphics.pose().translate(0.0F, 0.0F, 4.0F);
        Vector3f vector3f = this.getSignTextScale();
        guiGraphics.pose().scale(vector3f.x(), vector3f.y(), vector3f.z());
        int i = this.text.getColor().getTextColor();
        boolean flag = this.frame / 6 % 2 == 0;
        int j = 0;
        if (this.signField != null) {
            j = this.signField.getCursorPos();
        }
        int k = 0;
        if (this.signField != null) {
            k = this.signField.getSelectionPos();
        }
        int l = 4 * this.item.getTextLineHeight() / 2;
        int i1 = this.line * this.item.getTextLineHeight() - l;

        int j1;
        String s1;
        int l3;
        int i4;
        int j4;
        for(j1 = 0; j1 < this.messages.length; ++j1) {
            s1 = this.messages[j1];
            if (s1 != null) {
                if (this.font.isBidirectional()) {
                    s1 = this.font.bidirectionalShaping(s1);
                }

                l3 = -this.font.width(s1) / 2;
                guiGraphics.drawString(this.font, s1, l3, j1 * this.item.getTextLineHeight() - l, i, false);
                if (j1 == this.line && j >= 0 && flag) {
                    i4 = this.font.width(s1.substring(0, Math.min(j, s1.length())));
                    j4 = i4 - this.font.width(s1) / 2;
                    if (j >= s1.length()) {
                        guiGraphics.drawString(this.font, "_", j4, i1, i, false);
                    }
                }
            }
        }

        for(j1 = 0; j1 < this.messages.length; ++j1) {
            s1 = this.messages[j1];
            if (s1 != null && j1 == this.line && j >= 0) {
                l3 = this.font.width(s1.substring(0, Math.min(j, s1.length())));
                i4 = l3 - this.font.width(s1) / 2;
                if (flag && j < s1.length()) {
                    guiGraphics.fill(i4, i1 - 1, i4 + 1, i1 + this.item.getTextLineHeight(), -16777216 | i);
                }

                if (k != j) {
                    j4 = Math.min(j, k);
                    int j2 = Math.max(j, k);
                    int k2 = this.font.width(s1.substring(0, j4)) - this.font.width(s1) / 2;
                    int l2 = this.font.width(s1.substring(0, j2)) - this.font.width(s1) / 2;
                    int i3 = Math.min(k2, l2);
                    int j3 = Math.max(k2, l2);
                    guiGraphics.fill(RenderType.guiTextHighlight(), i3, i1, j3, i1 + this.item.getTextLineHeight(), -16776961);
                }
            }
        }

    }

    private void setMessage(String message) {
        this.messages[this.line] = message;
        this.text = this.text.setMessage(this.line, Component.literal(message));
        this.item.setText(itemStack, this.text);
    }

    private void onDone() {
        if (this.minecraft != null) {
            this.minecraft.setScreen(null);
        }
    }
}
