package de.blight.game.config;

import java.util.ArrayList;
import java.util.List;

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.KeyInput;
import com.jme3.input.MouseInput;
import com.jme3.input.RawInputListener;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.input.event.JoyAxisEvent;
import com.jme3.input.event.JoyButtonEvent;
import com.jme3.input.event.KeyInputEvent;
import com.jme3.input.event.MouseButtonEvent;
import com.jme3.input.event.MouseMotionEvent;
import com.jme3.input.event.TouchEvent;
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;

/**
 * Overlay-AppState der die Tastenbelegungs-Maske anzeigt.
 *
 * ESC           → Schließen (ohne Speichern)
 * Klick auf Row → wartet auf neue Taste
 * ESC während Warten → bricht nur die Zuweisung ab
 * Speichern     → schreibt JSON, ruft onSave-Callback
 */
public class ConfigScreen extends BaseAppState implements RawInputListener {

    // Farben
    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_ROW_HOVER  = new ColorRGBA(0.25f, 0.25f, 0.40f, 1.00f);
    private static final ColorRGBA COL_ROW_WAIT   = new ColorRGBA(0.50f, 0.30f, 0.10f, 1.00f);
    private static final ColorRGBA COL_BTN_SAVE   = 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_KEY   = new ColorRGBA(0.85f, 0.85f, 0.50f, 1.00f);

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

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

    private KeyBindings liveBindings; // geteilt mit der ganzen App
    private KeyBindings editCopy;     // wird beim Öffnen geklont

    private Runnable onSave;          // Callback → PlayerInputControl.reloadBindings
    private Runnable onClose;         // Callback → PauseMenu wiederherstellen

    private Node        panel;
    private List<Row>   rows = new ArrayList<>();
    private int         waitingRow = -1;    // -1 = keine Zuweisung aktiv

    // UI-Elemente für Buttons (Bounds in Screen-Koordinaten)
    private float saveBtnX, saveBtnY, saveBtnW, saveBtnH;
    private float cancelBtnX, cancelBtnY;

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

    private static class Row {
        String    field;
        String    label;
        BitmapText keyText;
        Geometry  bg;
        float     x, y, w, h; // Button-Bounds
    }

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

    public ConfigScreen(KeyBindings liveBindings, Runnable onSave) {
        this.liveBindings = liveBindings;
        this.onSave       = onSave;
    }

    public boolean isWaiting() { return waitingRow >= 0; }

    public void setOnClose(Runnable onClose) { this.onClose = onClose; }

    public void cancelWaiting() {
        if (waitingRow >= 0) { resetRowColor(waitingRow); waitingRow = -1; }
    }

    // -----------------------------------------------------------------------
    // Lifecycle
    // -----------------------------------------------------------------------

    @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() {
        editCopy   = liveBindings.copy();
        waitingRow = -1;
        buildUI();
        app.getInputManager().setCursorVisible(true);
        app.getInputManager().addRawInputListener(this);
        app.getInputManager().addMapping("_CfgClick", new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
        app.getInputManager().addListener(clickListener, "_CfgClick");
    }

    @Override
    protected void onDisable() {
        if (panel != null) { guiNode.detachChild(panel); panel = null; }
        rows.clear();
        waitingRow = -1;
        app.getInputManager().removeRawInputListener(this);
        app.getInputManager().deleteMapping("_CfgClick");
        app.getInputManager().setCursorVisible(false);
    }

    @Override protected void cleanup(Application app) {}

    // -----------------------------------------------------------------------
    // UI aufbauen
    // -----------------------------------------------------------------------

    private void buildUI() {
        float sw = app.getCamera().getWidth();
        float sh = app.getCamera().getHeight();

        panel = new Node("cfg-panel");

        // Halbdurchsichtiger Overlay über dem Spiel
        addQuad(panel, 0, 0, sw, sh, COL_BG, -2);

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

        // Titel
        BitmapText title = text("TASTENBELEGUNG", 20, COL_TEXT);
        centerText(title, px, py + ph - 40, pw);
        panel.attachChild(title);

        BitmapText hint = text("Klicke eine Taste um sie neu zu belegen", 14, new ColorRGBA(0.7f, 0.7f, 0.7f, 1f));
        centerText(hint, px, py + ph - 70, pw);
        panel.attachChild(hint);

        // Reihen
        float rowX   = px + 30;
        float keyX   = px + pw - 220;
        float rowW   = 180;
        float rowH   = 36;
        float startY = py + ph - 110;
        float stepY  = 48;

        for (int i = 0; i < KeyBindings.ENTRIES.length; i++) {
            String[] entry = KeyBindings.ENTRIES[i];
            float ry = startY - i * stepY;

            BitmapText lbl = text(entry[1], 16, COL_TEXT);
            lbl.setLocalTranslation(rowX, ry + rowH - 8, 0);
            panel.attachChild(lbl);

            Geometry bg = addQuad(panel, keyX, ry, rowW, rowH, COL_ROW, 0);

            BitmapText kt = text(KeyNames.of(editCopy.get(entry[0])), 16, COL_TEXT_KEY);
            kt.setLocalTranslation(keyX + 10, ry + rowH - 8, 1);
            panel.attachChild(kt);

            Row row = new Row();
            row.field   = entry[0];
            row.label   = entry[1];
            row.keyText = kt;
            row.bg      = bg;
            row.x = keyX; row.y = ry; row.w = rowW; row.h = rowH;
            rows.add(row);
        }

        // Buttons
        float btnW = 160, btnH = 42;
        float btnY = py + 25;
        saveBtnX   = px + pw / 2f - btnW - 15;
        saveBtnY   = btnY;
        saveBtnW   = btnW;
        saveBtnH   = btnH;
        cancelBtnX = px + pw / 2f + 15;
        cancelBtnY = btnY;

        addQuad(panel, saveBtnX, saveBtnY, btnW, btnH, COL_BTN_SAVE, 0);
        BitmapText saveLabel = text("Speichern", 16, COL_TEXT);
        centerText(saveLabel, saveBtnX, saveBtnY + btnH - 10, btnW);
        panel.attachChild(saveLabel);

        addQuad(panel, cancelBtnX, cancelBtnY, btnW, btnH, COL_BTN_CANCEL, 0);
        BitmapText cancelLabel = text("Abbrechen", 16, COL_TEXT);
        centerText(cancelLabel, cancelBtnX, cancelBtnY + btnH - 10, btnW);
        panel.attachChild(cancelLabel);

        guiNode.attachChild(panel);
    }

    // -----------------------------------------------------------------------
    // Mausklick
    // -----------------------------------------------------------------------

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

        // Reihen prüfen
        for (int i = 0; i < rows.size(); i++) {
            Row r = rows.get(i);
            if (hits(cursor, r.x, r.y, r.w, r.h)) {
                waitingRow = i;
                r.bg.getMaterial().setColor("Color", COL_ROW_WAIT);
                r.keyText.setText("...");
                return;
            }
        }

        // Speichern
        if (hits(cursor, saveBtnX, saveBtnY, saveBtnW, saveBtnH)) {
            liveBindings.copyFrom(editCopy);
            KeyBindingStore.save(liveBindings);
            if (onSave != null) onSave.run();
            setEnabled(false);
            if (onClose != null) onClose.run();
            return;
        }

        // Abbrechen
        if (hits(cursor, cancelBtnX, cancelBtnY, saveBtnW, saveBtnH)) {
            setEnabled(false);
            if (onClose != null) onClose.run();
        }
    };

    // -----------------------------------------------------------------------
    // Tastendruck beim Warten auf Zuweisung (RawInputListener)
    // -----------------------------------------------------------------------

    @Override
    public void onKeyEvent(KeyInputEvent evt) {
        if (!evt.isPressed() || waitingRow < 0) return;
        if (evt.getKeyCode() == KeyInput.KEY_ESCAPE) return; // cancelWaiting() wird von BlightApp aufgerufen

        Row r = rows.get(waitingRow);
        editCopy.set(r.field, evt.getKeyCode());
        r.keyText.setText(KeyNames.of(evt.getKeyCode()));
        resetRowColor(waitingRow);
        waitingRow = -1;
    }

    private void resetRowColor(int idx) {
        rows.get(idx).bg.getMaterial().setColor("Color", COL_ROW);
    }

    // RawInputListener-Pflichtmethoden
    @Override public void beginInput() {}
    @Override public void endInput() {}
    @Override public void onMouseMotionEvent(MouseMotionEvent evt) {}
    @Override public void onMouseButtonEvent(MouseButtonEvent evt) {}
    @Override public void onJoyAxisEvent(JoyAxisEvent evt) {}
    @Override public void onJoyButtonEvent(JoyButtonEvent evt) {}
    @Override public void onTouchEvent(TouchEvent evt) {}

    // -----------------------------------------------------------------------
    // Hilfsmethoden
    // -----------------------------------------------------------------------

    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 text(String content, int size, ColorRGBA color) {
        BitmapText t = new BitmapText(font, false);
        t.setSize(size);
        t.setColor(color);
        t.setText(content);
        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;
    }
}
