package top.leisuretimedock.dglabgame.client.gui;

import com.lowdragmc.lowdraglib.gui.texture.ColorRectTexture;
import com.lowdragmc.lowdraglib.gui.texture.ResourceBorderTexture;
import com.lowdragmc.lowdraglib.gui.texture.ResourceTexture;
import com.lowdragmc.lowdraglib.gui.texture.TextTexture;
import com.lowdragmc.lowdraglib.gui.widget.*;
import com.r3944realms.dg_lab.api.manager.Status;
import com.r3944realms.dg_lab.api.message.IPowerBoxMsg;
import com.r3944realms.dg_lab.api.message.argType.Channel;
import com.r3944realms.dg_lab.api.message.argType.ChangePolicy;
import com.r3944realms.dg_lab.api.message.data.PulseWaveListGenerator;
import com.r3944realms.dg_lab.api.websocket.message.MessageDirection;
import com.r3944realms.dg_lab.api.websocket.message.PowerBoxMessage;
import com.r3944realms.dg_lab.manager.DGPBClientManager;
import com.r3944realms.dg_lab.websocket.sharedData.ClientPowerBoxSharedData;
import net.minecraft.client.Minecraft;
import net.minecraft.network.chat.Component;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import top.leisuretimedock.dglabgame.config.ClientConfig;
import top.leisuretimedock.dglabgame.config.CommonConfig;
import top.leisuretimedock.dglabgame.core.manager.DGLabManagerHolder;
import top.leisuretimedock.dglabgame.core.manager.ServerManager;
import top.leisuretimedock.dglabgame.core.network.DLGNetworkHandler;
import top.leisuretimedock.dglabgame.core.network.toServer.UpdateServerConfigPacket;
import top.leisuretimedock.dglabgame.core.network.toServer.UpdateStrengthConfigPacket;

import java.awt.*;
import java.awt.datatransfer.StringSelection;
import java.util.Optional;

@OnlyIn(Dist.CLIENT)
public class DGLabManagementGui implements ILdlibGui {
    private static final int W = 380;
    private static final int H = 260;
    private static final String CLIENT_ID = "dglabgame-gui";
    private String currentPage = "qrcode";

    @Override
    public WidgetGroup createGui() {
        WidgetGroup root = new WidgetGroup(0, 0, W, H);
        root.setBackground(new ColorRectTexture(0xff1a1a1a));

        // top nav bar
        root.addWidget(navButton("qrcode", 5, 5, 55, 18, "gui.dglabgame.tab.qrcode"));
        root.addWidget(navButton("strength", 65, 5, 55, 18, "gui.dglabgame.tab.strength"));
        root.addWidget(navButton("waveform", 125, 5, 55, 18, "gui.dglabgame.tab.waveform"));
        root.addWidget(navButton("feedback", 185, 5, 55, 18, "gui.dglabgame.tab.feedback"));

        boolean isAdmin = Minecraft.getInstance().player != null
                && Minecraft.getInstance().player.hasPermissions(4);
        if (isAdmin) {
            root.addWidget(navButton("server", 245, 5, 55, 18, "gui.dglabgame.tab.server"));
        }

        // content area
        root.addWidget(buildContentArea());

        // bottom bar: client selector
        root.addWidget(buildBottomBar());

        return root;
    }

    private ButtonWidget navButton(String page, int x, int y, int w, int h, String langKey) {
        ButtonWidget btn = new ButtonWidget(x, y, w, h,
                new TextTexture(Component.translatable(langKey).getString(), 0xffffffff),
                cd -> switchPage(page)
        );
        btn.setBackground(new ColorRectTexture(page.equals(currentPage) ? 0xff4444aa : 0xff333333));
        return btn;
    }

    private void switchPage(String page) {
        currentPage = page;
        display();
    }

    private WidgetGroup buildContentArea() {
        WidgetGroup area = new WidgetGroup(5, 28, W - 10, H - 62);
        area.setBackground(new ColorRectTexture(0xff222222));

        switch (currentPage) {
            case "qrcode": buildQrCodeTab(area); break;
            case "strength": buildStrengthTab(area); break;
            case "waveform": buildWaveformTab(area); break;
            case "feedback": buildFeedbackTab(area); break;
            case "server": buildServerTab(area); break;
        }
        return area;
    }

    // ==================== QR Code Tab ====================

    private void buildQrCodeTab(WidgetGroup group) {
        int y = 10;
        TextFieldWidget urlField = new TextFieldWidget(10, y, W - 40, 15, () -> "", s -> {});
        urlField.setCurrentString("");
        urlField.setBordered(true);
        group.addWidget(urlField);

        group.addWidget(new ButtonWidget(W - 45, y, 22, 15, cd -> {
            String url = getQrCodeUrl();
            Toolkit.getDefaultToolkit().getSystemClipboard()
                    .setContents(new StringSelection(url), null);
        }).setBackground(new ColorRectTexture(0xff336633)));

        y += 22;
        group.addWidget(new ImageWidget(10, y, W - 40, 14,
                new TextTexture(Component.translatable("gui.dglabgame.qrcode.copy").getString(), 0xffaaaaaa)));

        y += 20;
        var names = DGLabManagerHolder.getClientManager().getClientNames();
        for (String name : names) {
            group.addWidget(new ImageWidget(10, y, W - 40, 10,
                    new TextTexture(name, 0xffcccccc)));
            y += 14;
        }
    }

    private String getQrCodeUrl() {
        var names = DGLabManagerHolder.getClientManager().getClientNames();
        for (String name : names) {
            Optional<DGPBClientManager> client = DGLabManagerHolder.getClientManager().getClient(name);
            if (client.isPresent()) {
                ClientPowerBoxSharedData sd = client.get().getSharedData();
                if (sd != null && sd.rqCodeUrl != null && !sd.rqCodeUrl.isEmpty()) {
                    return sd.rqCodeUrl;
                }
            }
        }
        return "";
    }

    // ==================== Strength Tab ====================

    private void buildStrengthTab(WidgetGroup group) {
        int y = 8;
        group.addWidget(new ImageWidget(10, y, 60, 10,
                new TextTexture(Component.translatable("gui.dglabgame.strength.channel_a").getString(), 0xffff4444)));

        y += 14;
        group.addWidget(strengthField("maxA", W / 2 - 55, y, CommonConfig.MAX_STRENGTH_A.get()));
        group.addWidget(strengthField("minA", W / 2 + 15, y, CommonConfig.MIN_STRENGTH_A.get()));

        y += 20;
        group.addWidget(new ImageWidget(10, y, 60, 10,
                new TextTexture(Component.translatable("gui.dglabgame.strength.channel_b").getString(), 0xff4444ff)));

        y += 14;
        group.addWidget(strengthField("maxB", W / 2 - 55, y, CommonConfig.MAX_STRENGTH_B.get()));
        group.addWidget(strengthField("minB", W / 2 + 15, y, CommonConfig.MIN_STRENGTH_B.get()));

        y += 22;
        group.addWidget(new ButtonWidget(W / 2 - 30, y, 60, 16, cd -> {
            TextFieldWidget maxAF = (TextFieldWidget) group.getFirstWidgetById("maxA");
            TextFieldWidget minAF = (TextFieldWidget) group.getFirstWidgetById("minA");
            TextFieldWidget maxBF = (TextFieldWidget) group.getFirstWidgetById("maxB");
            TextFieldWidget minBF = (TextFieldWidget) group.getFirstWidgetById("minB");
            try {
                int maxA = Integer.parseInt(maxAF.getCurrentString());
                int minA = Integer.parseInt(minAF.getCurrentString());
                int maxB = Integer.parseInt(maxBF.getCurrentString());
                int minB = Integer.parseInt(minBF.getCurrentString());
                DLGNetworkHandler.CHANNEL.sendToServer(new UpdateStrengthConfigPacket(maxA, minA, maxB, minB));
            } catch (NumberFormatException ignored) {}
        }).setBackground(new ColorRectTexture(0xff336633)));
    }

    private TextFieldWidget strengthField(String id, int x, int y, int value) {
        TextFieldWidget field = new TextFieldWidget(x, y, 50, 14, () -> "", s -> {});
        field.setCurrentString(String.valueOf(value));
        field.setBordered(true);
        field.setId(id);
        return field;
    }

    // ==================== Waveform Tab ====================

    private void buildWaveformTab(WidgetGroup group) {
        int y = 8;
        String[] labels = {"f1", "s1", "f2", "s2", "f3", "s3", "f4", "s4"};
        int[] defaults = {80, 50, 80, 50, 80, 50, 80, 50};

        group.addWidget(new ImageWidget(10, y, 80, 10,
                new TextTexture(Component.translatable("gui.dglabgame.waveform.channel").getString(), 0xffcccccc)));

        group.addWidget(new ButtonWidget(W / 2 + 40, y - 2, 40, 14, cd -> {})
                .setBackground(new ColorRectTexture(0xff4444aa)));

        y += 16;
        for (int i = 0; i < 4; i++) {
            int fx = 10 + i * (W - 20) / 4;
            TextFieldWidget ff = new TextFieldWidget(fx, y, 35, 12, () -> "", s -> {});
            ff.setCurrentString(String.valueOf(defaults[i * 2]));
            ff.setBordered(true);
            ff.setId("wf_f" + (i + 1));
            group.addWidget(ff);

            TextFieldWidget sf = new TextFieldWidget(fx + 40, y, 35, 12, () -> "", s -> {});
            sf.setCurrentString(String.valueOf(defaults[i * 2 + 1]));
            sf.setBordered(true);
            sf.setId("wf_s" + (i + 1));
            group.addWidget(sf);
        }

        y += 18;
        group.addWidget(new ButtonWidget(W / 2 - 30, y, 60, 16, cd -> {
            try {
                int f1 = parseIntField(group, "wf_f1"), f2 = parseIntField(group, "wf_f2");
                int f3 = parseIntField(group, "wf_f3"), f4 = parseIntField(group, "wf_f4");
                int s1 = parseIntField(group, "wf_s1"), s2 = parseIntField(group, "wf_s2");
                int s3 = parseIntField(group, "wf_s3"), s4 = parseIntField(group, "wf_s4");

                var waveList = PulseWaveListGenerator.pulseWave(
                        new int[]{f1, f2, f3, f4}, new int[]{s1, s2, s3, s4});
                IPowerBoxMsg.Pulse msg = new IPowerBoxMsg.Pulse(Channel.A, waveList, 0);
                PowerBoxMessage pbm = msg.toPowerBoxMessage(CLIENT_ID, CLIENT_ID,
                        MessageDirection.DirectType.CLIENT_TO_SERVER);
                DGLabManagerHolder.getServerManager().ifPresent(mgr -> mgr.sendToAll(pbm));
            } catch (NumberFormatException ignored) {}
        }).setBackground(new ColorRectTexture(0xff994400)));

        group.addWidget(new ButtonWidget(W / 2 + 38, y, 60, 16, cd -> {
            try {
                int f1 = parseIntField(group, "wf_f1"), f2 = parseIntField(group, "wf_f2");
                int f3 = parseIntField(group, "wf_f3"), f4 = parseIntField(group, "wf_f4");
                int s1 = parseIntField(group, "wf_s1"), s2 = parseIntField(group, "wf_s2");
                int s3 = parseIntField(group, "wf_s3"), s4 = parseIntField(group, "wf_s4");

                var waveList = PulseWaveListGenerator.pulseWave(
                        new int[]{f1, f2, f3, f4}, new int[]{s1, s2, s3, s4});
                IPowerBoxMsg.Clear clear = new IPowerBoxMsg.Clear(Channel.A);
                IPowerBoxMsg.Pulse pulse = new IPowerBoxMsg.Pulse(Channel.A, waveList, 0);
                PowerBoxMessage clearMsg = clear.toPowerBoxMessage(CLIENT_ID, CLIENT_ID,
                        MessageDirection.DirectType.CLIENT_TO_SERVER);
                PowerBoxMessage pulseMsg = pulse.toPowerBoxMessage(CLIENT_ID, CLIENT_ID,
                        MessageDirection.DirectType.CLIENT_TO_SERVER);
                DGLabManagerHolder.getServerManager().ifPresent(mgr -> {
                    mgr.sendToAll(clearMsg);
                    mgr.sendToAll(pulseMsg);
                });
            } catch (NumberFormatException ignored) {}
        }).setBackground(new ColorRectTexture(0xff994400)));
    }

    private int parseIntField(WidgetGroup group, String id) {
        Widget w = group.getFirstWidgetById(id);
        if (w instanceof TextFieldWidget tf) {
            return Integer.parseInt(tf.getCurrentString());
        }
        throw new NumberFormatException();
    }

    // ==================== Feedback Tab ====================

    private void buildFeedbackTab(WidgetGroup group) {
        int y = 8;
        group.addWidget(new ImageWidget(10, y, 80, 10,
                new TextTexture(Component.translatable("gui.dglabgame.feedback.send").getString(), 0xffcccccc)));

        y += 16;
        var presets = ClientConfig.FEEDBACK_PRESETS.get();
        int cols = 4;
        int btnW = (W - 30) / cols;
        int row = 0, col = 0;
        for (String presetStr : presets) {
            try {
                int val = Integer.parseInt(presetStr.trim());
                int bx = 10 + col * (btnW + 2);
                int by = y + row * 18;
                group.addWidget(new ButtonWidget(bx, by, btnW, 14, cd -> sendFeedback(val))
                        .setBackground(new ColorRectTexture(0xff444488)));
                col++;
                if (col >= cols) { col = 0; row++; }
            } catch (NumberFormatException ignored) {}
        }

        y += (row + 1) * 18 + 6;
        TextFieldWidget customField = new TextFieldWidget(10, y, 50, 14, () -> "", s -> {});
        customField.setCurrentString("5");
        customField.setBordered(true);
        customField.setId("feedback_custom");
        group.addWidget(customField);

        group.addWidget(new ButtonWidget(65, y, 50, 14, cd -> {
            try {
                TextFieldWidget f = (TextFieldWidget) group.getFirstWidgetById("feedback_custom");
                sendFeedback(Integer.parseInt(f.getCurrentString()));
            } catch (NumberFormatException ignored) {}
        }).setBackground(new ColorRectTexture(0xff444488)));
    }

    private void sendFeedback(int value) {
        IPowerBoxMsg.Feedback msg = new IPowerBoxMsg.Feedback(Math.max(0, Math.min(10, value)));
        PowerBoxMessage pbm = msg.toPowerBoxMessage(CLIENT_ID, CLIENT_ID,
                MessageDirection.DirectType.CLIENT_TO_SERVER);
        DGLabManagerHolder.getServerManager().ifPresent(mgr -> mgr.sendToAll(pbm));
    }

    // ==================== Server Tab ====================

    private void buildServerTab(WidgetGroup group) {
        int y = 8;
        group.addWidget(new ImageWidget(10, y, 60, 10,
                new TextTexture(Component.translatable("gui.dglabgame.server.port").getString(), 0xffcccccc)));
        TextFieldWidget portField = new TextFieldWidget(80, y, 60, 14, () -> "", s -> {});
        portField.setCurrentString(String.valueOf(CommonConfig.SERVER_PORT.get()));
        portField.setBordered(true);
        portField.setId("server_port");
        group.addWidget(portField);

        y += 18;
        group.addWidget(new ImageWidget(10, y, 60, 10,
                new TextTexture(Component.translatable("gui.dglabgame.server.max_conn").getString(), 0xffcccccc)));
        TextFieldWidget maxField = new TextFieldWidget(80, y, 60, 14, () -> "", s -> {});
        maxField.setCurrentString(String.valueOf(CommonConfig.MAX_CONNECTIONS.get()));
        maxField.setBordered(true);
        maxField.setId("max_connections");
        group.addWidget(maxField);

        y += 20;
        group.addWidget(new ButtonWidget(10, y, 60, 16, cd -> {
            try {
                TextFieldWidget pf = (TextFieldWidget) group.getFirstWidgetById("server_port");
                TextFieldWidget mf = (TextFieldWidget) group.getFirstWidgetById("max_connections");
                int port = Integer.parseInt(pf.getCurrentString());
                int max = Integer.parseInt(mf.getCurrentString());
                DLGNetworkHandler.CHANNEL.sendToServer(new UpdateServerConfigPacket(port, max));
            } catch (NumberFormatException ignored) {}
        }).setBackground(new ColorRectTexture(0xff336633)));

        Optional<ServerManager> mgr = DGLabManagerHolder.getServerManager();
        String statusText = mgr.map(m -> m.getStatus().name()).orElse("NO SERVER");
        group.addWidget(new ImageWidget(80, y + 2, 120, 10,
                new TextTexture(Component.translatable("gui.dglabgame.server.status", statusText).getString(), 0xffaaaaaa)));

        y += 20;
        group.addWidget(new ButtonWidget(10, y, 60, 16, cd -> {
            Optional<ServerManager> sm = DGLabManagerHolder.getServerManager();
            if (sm.isEmpty() || sm.get().getStatus() == Status.STOPPED) {
                DGLabManagerHolder.getOrCreateServerManager().start();
            }
        }).setBackground(new ColorRectTexture(0xff226622)));

        group.addWidget(new ButtonWidget(80, y, 60, 16, cd -> {
            DGLabManagerHolder.getServerManager().ifPresent(ServerManager::stop);
        }).setBackground(new ColorRectTexture(0xff662222)));
    }

    // ==================== Bottom Bar ====================

    private WidgetGroup buildBottomBar() {
        WidgetGroup bar = new WidgetGroup(5, H - 30, W - 10, 22);
        bar.setBackground(ResourceBorderTexture.BORDERED_BACKGROUND);

        bar.addWidget(new ImageWidget(10, 4, 40, 10,
                new TextTexture(Component.translatable("gui.dglabgame.client.label").getString(), 0xffaaaaaa)));

        var names = DGLabManagerHolder.getClientManager().getClientNames();
        String current = names.isEmpty() ? "none" : names.iterator().next();

        bar.addWidget(new ButtonWidget(55, 2, 60, 14, cd -> {
            DGLabManagerHolder.getClientManager().getClient(current).ifPresent(DGPBClientManager::start);
        }).setBackground(new ColorRectTexture(0xff226622)));

        bar.addWidget(new ButtonWidget(120, 2, 60, 14, cd -> {
            DGLabManagerHolder.getClientManager().getClient(current).ifPresent(DGPBClientManager::stop);
        }).setBackground(new ColorRectTexture(0xff662222)));

        return bar;
    }
}
