package de.blight.game.config;

import com.jme3.app.Application;
import com.jme3.app.SimpleApplication;
import com.jme3.app.state.BaseAppState;
import com.jme3.font.BitmapFont;
import com.jme3.font.BitmapText;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.material.Material;
import com.jme3.material.RenderState;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector2f;
import com.jme3.renderer.queue.RenderQueue;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.shape.Quad;
import com.jme3.system.AppSettings;

public class GraphicsScreen extends BaseAppState {

    private static final ColorRGBA COL_BG        = new ColorRGBA(0.05f, 0.05f, 0.08f, 0.88f);
    private static final ColorRGBA COL_PANEL      = new ColorRGBA(0.10f, 0.10f, 0.16f, 1.00f);
    private static final ColorRGBA COL_ROW        = new ColorRGBA(0.18f, 0.18f, 0.28f, 1.00f);
    private static final ColorRGBA COL_ARROW      = new ColorRGBA(0.28f, 0.28f, 0.44f, 1.00f);
    private static final ColorRGBA COL_BTN_OK     = new ColorRGBA(0.15f, 0.40f, 0.15f, 1.00f);
    private static final ColorRGBA COL_BTN_CANCEL = new ColorRGBA(0.40f, 0.15f, 0.15f, 1.00f);
    private static final ColorRGBA COL_TEXT       = ColorRGBA.White;
    private static final ColorRGBA COL_TEXT_VAL   = new ColorRGBA(0.85f, 0.85f, 0.50f, 1.00f);

    private static final int[][] RESOLUTIONS = {
        {1280, 720}, {1600, 900}, {1920, 1080}, {2560, 1440}, {3840, 2160}
    };
    private static final int[] SAMPLES = {0, 2, 4, 8};

    private static final int ROW_RES   = 0;
    private static final int ROW_FULL  = 1;
    private static final int ROW_VSYNC = 2;
    private static final int ROW_AA    = 3;

    private SimpleApplication app;
    private Node guiNode;
    private BitmapFont font;
    private Node panel;

    private final GraphicsSettings live;
    private GraphicsSettings edit;
    private final Runnable onClose;

    private int resIdx;
    private int samplesIdx;

    // Per-row layout (indexed by ROW_*)
    private final float[] cellX = new float[4];
    private final float[] cellY = new float[4];
    private final float[] cellW = new float[4];
    private final float   cellH = 36;
    private final float   arrW  = 30;
    private final float[] leftX  = new float[4];
    private final float[] rightX = new float[4];
    private final BitmapText[] valTexts = new BitmapText[4];

    private float okX, okY, okW, okH;
    private float cancelX, cancelY;

    public GraphicsScreen(GraphicsSettings live, Runnable onClose) {
        this.live    = live;
        this.onClose = onClose;
    }

    @Override
    protected void initialize(Application app) {
        this.app     = (SimpleApplication) app;
        this.guiNode = this.app.getGuiNode();
        this.font    = app.getAssetManager().loadFont("Interface/Fonts/Default.fnt");
    }

    @Override
    protected void onEnable() {
        edit = new GraphicsSettings();
        edit.width = live.width; edit.height = live.height;
        edit.fullscreen = live.fullscreen;
        edit.vsync = live.vsync;
        edit.samples = live.samples;

        resIdx = 0;
        for (int i = 0; i < RESOLUTIONS.length; i++) {
            if (RESOLUTIONS[i][0] == edit.width && RESOLUTIONS[i][1] == edit.height) {
                resIdx = i; break;
            }
        }
        samplesIdx = 0;
        for (int i = 0; i < SAMPLES.length; i++) {
            if (SAMPLES[i] == edit.samples) { samplesIdx = i; break; }
        }

        buildUI();
        app.getInputManager().setCursorVisible(true);
        app.getInputManager().addMapping("_GfxClick", new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
        app.getInputManager().addListener(clickListener, "_GfxClick");
    }

    @Override
    protected void onDisable() {
        if (panel != null) { guiNode.detachChild(panel); panel = null; }
        app.getInputManager().deleteMapping("_GfxClick");
        app.getInputManager().setCursorVisible(false);
    }

    @Override protected void cleanup(Application app) {}

    private void buildUI() {
        float sw = app.getCamera().getWidth();
        float sh = app.getCamera().getHeight();
        panel = new Node("gfx-panel");
        addQuad(panel, 0, 0, sw, sh, COL_BG, -2);

        float pw = 640, ph = 400;
        float px = (sw - pw) / 2f, py = (sh - ph) / 2f;
        addQuad(panel, px, py, pw, ph, COL_PANEL, -1);

        BitmapText title = txt("GRAFIKEINSTELLUNGEN", 20, COL_TEXT);
        centerText(title, px, py + ph - 42, pw);
        panel.attachChild(title);

        String[] labels  = {"Auflösung", "Vollbild", "VSync", "Kantenglättung"};
        float lblX   = px + 30;
        float vx     = px + pw - 270;
        float vw     = 190;
        float startY = py + ph - 100;
        float step   = 60;

        for (int i = 0; i < 4; i++) {
            float ry = startY - i * step;

            BitmapText lbl = txt(labels[i], 16, COL_TEXT);
            lbl.setLocalTranslation(lblX, ry + cellH - 8, 0);
            panel.attachChild(lbl);

            // Left arrow
            addQuad(panel, vx - arrW - 6, ry, arrW, cellH, COL_ARROW, 0);
            BitmapText lt = txt("<", 16, COL_TEXT);
            lt.setLocalTranslation(vx - arrW - 6 + (arrW - lt.getLineWidth()) / 2f, ry + cellH - 8, 1);
            panel.attachChild(lt);

            // Value cell
            addQuad(panel, vx, ry, vw, cellH, COL_ROW, 0);

            // Right arrow
            addQuad(panel, vx + vw + 6, ry, arrW, cellH, COL_ARROW, 0);
            BitmapText rt = txt(">", 16, COL_TEXT);
            rt.setLocalTranslation(vx + vw + 6 + (arrW - rt.getLineWidth()) / 2f, ry + cellH - 8, 1);
            panel.attachChild(rt);

            BitmapText vt = txt("", 16, COL_TEXT_VAL);
            panel.attachChild(vt);
            valTexts[i] = vt;

            cellX[i] = vx; cellY[i] = ry; cellW[i] = vw;
            leftX[i]  = vx - arrW - 6;
            rightX[i] = vx + vw + 6;
        }

        for (int i = 0; i < 4; i++) refreshText(i);

        float bw = 160, bh = 42;
        okW = bw; okH = bh;
        okX = px + pw / 2f - bw - 10;
        okY = py + 22;
        cancelX = px + pw / 2f + 10;
        cancelY = py + 22;

        addQuad(panel, okX, okY, bw, bh, COL_BTN_OK, 0);
        BitmapText okLbl = txt("Übernehmen", 16, COL_TEXT);
        centerText(okLbl, okX, okY + bh - 10, bw);
        panel.attachChild(okLbl);

        addQuad(panel, cancelX, cancelY, bw, bh, COL_BTN_CANCEL, 0);
        BitmapText cancelLbl = txt("Abbrechen", 16, COL_TEXT);
        centerText(cancelLbl, cancelX, cancelY + bh - 10, bw);
        panel.attachChild(cancelLbl);

        guiNode.attachChild(panel);
    }

    private void refreshText(int row) {
        String val = switch (row) {
            case ROW_RES   -> RESOLUTIONS[resIdx][0] + "x" + RESOLUTIONS[resIdx][1];
            case ROW_FULL  -> edit.fullscreen ? "An" : "Aus";
            case ROW_VSYNC -> edit.vsync ? "An" : "Aus";
            case ROW_AA    -> SAMPLES[samplesIdx] == 0 ? "Aus" : SAMPLES[samplesIdx] + "x MSAA";
            default        -> "";
        };
        BitmapText vt = valTexts[row];
        vt.setText(val);
        vt.setLocalTranslation(
            cellX[row] + (cellW[row] - vt.getLineWidth()) / 2f,
            cellY[row] + cellH - 8,
            1
        );
    }

    private final ActionListener clickListener = (name, isPressed, tpf) -> {
        if (!isPressed) return;
        Vector2f c = app.getInputManager().getCursorPosition();

        for (int i = 0; i < 4; i++) {
            if (hits(c, leftX[i], cellY[i], arrW, cellH)) { cycleRow(i, -1); return; }
            if (hits(c, rightX[i], cellY[i], arrW, cellH)) { cycleRow(i, +1); return; }
        }
        if (hits(c, okX, okY, okW, okH))        { applyAndSave(); return; }
        if (hits(c, cancelX, cancelY, okW, okH)) { close(); }
    };

    private void cycleRow(int row, int dir) {
        switch (row) {
            case ROW_RES:
                resIdx = (resIdx + dir + RESOLUTIONS.length) % RESOLUTIONS.length;
                edit.width  = RESOLUTIONS[resIdx][0];
                edit.height = RESOLUTIONS[resIdx][1];
                break;
            case ROW_FULL:
                edit.fullscreen = !edit.fullscreen;
                break;
            case ROW_VSYNC:
                edit.vsync = !edit.vsync;
                break;
            case ROW_AA:
                samplesIdx = (samplesIdx + dir + SAMPLES.length) % SAMPLES.length;
                edit.samples = SAMPLES[samplesIdx];
                break;
        }
        refreshText(row);
    }

    private void applyAndSave() {
        live.width = edit.width; live.height = edit.height;
        live.fullscreen = edit.fullscreen;
        live.vsync = edit.vsync;
        live.samples = edit.samples;

        GraphicsStore.save(live);

        AppSettings s = app.getContext().getSettings();
        s.setResolution(live.width, live.height);
        s.setFullscreen(live.fullscreen);
        s.setVSync(live.vsync);
        s.setSamples(live.samples);
        app.setSettings(s);

        close();
        app.restart();
    }

    private void close() {
        setEnabled(false);
        if (onClose != null) onClose.run();
    }

    // -----------------------------------------------------------------------

    private Geometry addQuad(Node parent, float x, float y, float w, float h, ColorRGBA color, float z) {
        Geometry geo = new Geometry("q", new Quad(w, h));
        Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
        mat.setColor("Color", color.clone());
        if (color.a < 1f) {
            mat.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Alpha);
            geo.setQueueBucket(RenderQueue.Bucket.Transparent);
        }
        geo.setMaterial(mat);
        geo.setLocalTranslation(x, y, z);
        parent.attachChild(geo);
        return geo;
    }

    private BitmapText txt(String s, int size, ColorRGBA color) {
        BitmapText t = new BitmapText(font, false);
        t.setSize(size); t.setColor(color); t.setText(s);
        return t;
    }

    private void centerText(BitmapText t, float x, float y, float width) {
        t.setLocalTranslation(x + (width - t.getLineWidth()) / 2f, y, 1);
    }

    private boolean hits(Vector2f p, float x, float y, float w, float h) {
        return p.x >= x && p.x <= x + w && p.y >= y && p.y <= y + h;
    }
}
